From 28391d2f52599724c5df93037f20d0c0316c918c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 26 May 2016 17:46:44 +0200 Subject: [PATCH 01/88] Basic signing queue --- Cargo.lock | 6 ++ rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/types/mod.rs.in | 8 +- signer/Cargo.toml | 9 ++- signer/build.rs | 27 +++++++ signer/src/lib.rs | 9 +++ signer/src/signing_queue.rs | 74 +++++++++++++++++++ {rpc/src/v1 => signer/src}/types/bytes.rs | 17 ++++- signer/src/types/mod.rs | 21 ++++++ signer/src/types/mod.rs.in | 19 +++++ .../src}/types/transaction_request.rs | 7 +- 12 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 signer/src/signing_queue.rs rename {rpc/src/v1 => signer/src}/types/bytes.rs (77%) create mode 100644 signer/src/types/mod.rs create mode 100644 signer/src/types/mod.rs.in rename {rpc/src/v1 => signer/src}/types/transaction_request.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 11c04d77d..39404a419 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,6 +301,7 @@ dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore 1.2.0", + "ethcore-signer 1.2.0", "ethcore-util 1.2.0", "ethminer 1.2.0", "ethsync 1.2.0", @@ -324,7 +325,12 @@ dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-util 1.2.0", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2cdbb0a2b..c8bfa0485 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,6 +19,7 @@ ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethminer = { path = "../miner" } +ethcore-signer = { path = "../signer" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7d9818615..ae824adf2 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -27,6 +27,7 @@ extern crate serde_json; extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_util as util; +extern crate ethcore_signer as signer; extern crate ethcore; extern crate ethsync; extern crate ethminer; diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index d896a64dc..9b56221b5 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -14,31 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +// TODO import signer types + mod block; mod block_number; -mod bytes; mod filter; mod index; mod log; mod optionals; mod sync; mod transaction; -mod transaction_request; mod call_request; mod receipt; mod trace; mod trace_filter; +pub use signer::types::bytes::Bytes; +pub use signer::types::transaction_request::TransactionRequest; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; -pub use self::bytes::Bytes; pub use self::filter::Filter; pub use self::index::Index; pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; -pub use self::transaction_request::TransactionRequest; pub use self::call_request::CallRequest; pub use self::receipt::Receipt; pub use self::trace::Trace; diff --git a/signer/Cargo.toml b/signer/Cargo.toml index f72865f4f..0d7f562ab 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -9,13 +9,20 @@ build = "build.rs" [build-dependencies] rustc_version = "0.1" +serde_codegen = { version = "0.7.0", optional = true } +syntex = "^0.32.0" [dependencies] +serde = "0.7.0" +serde_json = "0.7.0" +serde_macros = { version = "0.7.0", optional = true } +rustc-serialize = "0.3" ethcore-util = { path = "../util" } log = "0.3" env_logger = "0.3" clippy = { version = "0.0.69", optional = true} [features] -default = [] +default = ["serde_codegen"] +nightly = ["serde_macros"] dev = ["clippy"] diff --git a/signer/build.rs b/signer/build.rs index 41b9a1b3e..2bcfc7da5 100644 --- a/signer/build.rs +++ b/signer/build.rs @@ -19,7 +19,34 @@ extern crate rustc_version; use rustc_version::{version_meta, Channel}; fn main() { + serde::main(); if let Channel::Nightly = version_meta().channel { println!("cargo:rustc-cfg=nightly"); } } + +#[cfg(not(feature = "serde_macros"))] +mod serde { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("mod.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod serde { + pub fn main() {} +} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index fd17758d2..ed8ec12ce 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -34,6 +34,15 @@ extern crate log; extern crate env_logger; +extern crate serde; +extern crate serde_json; +extern crate rustc_serialize; + +extern crate ethcore_util as util; + +mod signing_queue; +pub mod types; + #[cfg(test)] mod tests { #[test] diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs new file mode 100644 index 000000000..7758f5df3 --- /dev/null +++ b/signer/src/signing_queue.rs @@ -0,0 +1,74 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashSet; +use types::transaction_request::TransactionRequest; + +pub trait SigningQueue { + fn add_request(&mut self, transaction: TransactionRequest); + + fn remove_request(&mut self, id: TransactionRequest); + + fn requests(&self) -> &HashSet; +} + +impl SigningQueue for HashSet { + fn add_request(&mut self, transaction: TransactionRequest) { + self.insert(transaction); + } + + fn remove_request(&mut self, id: TransactionRequest) { + self.remove(&id); + } + + fn requests(&self) -> &HashSet { + self + } +} + + +#[cfg(test)] +mod test { + use std::collections::HashSet; + use util::hash::Address; + use util::numbers::U256; + use types::transaction_request::TransactionRequest; + use super::*; + + #[test] + fn should_work_for_hashset() { + // given + let mut queue = HashSet::new(); + + let request = TransactionRequest { + from: Address::from(1), + to: Some(Address::from(2)), + gas_price: None, + gas: None, + value: Some(U256::from(10_000_000)), + data: None, + nonce: None, + }; + + // when + queue.add_request(request.clone()); + let all = queue.requests(); + + // then + assert_eq!(all.len(), 1); + assert!(all.contains(&request)); + } +} diff --git a/rpc/src/v1/types/bytes.rs b/signer/src/types/bytes.rs similarity index 77% rename from rpc/src/v1/types/bytes.rs rename to signer/src/types/bytes.rs index 4febacec9..aa2772894 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/signer/src/types/bytes.rs @@ -14,6 +14,22 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + use rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; use serde::de::Visitor; @@ -80,4 +96,3 @@ mod tests { } } - diff --git a/signer/src/types/mod.rs b/signer/src/types/mod.rs new file mode 100644 index 000000000..adf9be071 --- /dev/null +++ b/signer/src/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 . + +#[cfg(feature = "serde_macros")] +include!("mod.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in new file mode 100644 index 000000000..7040780f3 --- /dev/null +++ b/signer/src/types/mod.rs.in @@ -0,0 +1,19 @@ +// 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_request; +pub mod bytes; diff --git a/rpc/src/v1/types/transaction_request.rs b/signer/src/types/transaction_request.rs similarity index 97% rename from rpc/src/v1/types/transaction_request.rs rename to signer/src/types/transaction_request.rs index f00fa9ef0..f95d7ff4c 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/signer/src/types/transaction_request.rs @@ -16,9 +16,9 @@ use util::hash::Address; use util::numbers::U256; -use v1::types::Bytes; +use types::bytes::Bytes; -#[derive(Debug, Default, PartialEq, Deserialize)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] pub struct TransactionRequest { pub from: Address, pub to: Option
, @@ -37,7 +37,7 @@ mod tests { use serde_json; use util::numbers::{U256}; use util::hash::Address; - use v1::types::Bytes; + use types::bytes::Bytes; use super::*; #[test] @@ -126,3 +126,4 @@ mod tests { }); } } + From a61bf90c17bb68ee7f1c599366f15b1efbd85795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 26 May 2016 18:33:08 +0200 Subject: [PATCH 02/88] Adding docs --- signer/src/lib.rs | 2 ++ signer/src/types/bytes.rs | 23 ++++++----------------- signer/src/types/mod.rs.in | 1 + signer/src/types/transaction_request.rs | 10 ++++++++++ 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/signer/src/lib.rs b/signer/src/lib.rs index ed8ec12ce..d8e7f63ec 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -17,6 +17,8 @@ #![warn(missing_docs)] #![cfg_attr(all(nightly, feature="dev"), feature(plugin))] #![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +// Generated by serde +#![cfg_attr(all(nightly, feature="dev"), allow(redundant_closure_call))] //! Signer module //! diff --git a/signer/src/types/bytes.rs b/signer/src/types/bytes.rs index aa2772894..d8896f849 100644 --- a/signer/src/types/bytes.rs +++ b/signer/src/types/bytes.rs @@ -14,27 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - use rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; use serde::de::Visitor; use util::common::FromHex; +///! Serializable wrapper around vector of bytes + /// Wrapper structure around vector of bytes. #[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] pub struct Bytes(pub Vec); @@ -44,7 +30,10 @@ impl Bytes { pub fn new(bytes: Vec) -> Bytes { Bytes(bytes) } - pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } + /// Convert back to vector + pub fn to_vec(self) -> Vec { + let Bytes(x) = self; x + } } impl Serialize for Bytes { diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in index 7040780f3..8e9befa4f 100644 --- a/signer/src/types/mod.rs.in +++ b/signer/src/types/mod.rs.in @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +///! Reusable types with JSON Serialization. pub mod transaction_request; pub mod bytes; diff --git a/signer/src/types/transaction_request.rs b/signer/src/types/transaction_request.rs index f95d7ff4c..83840515b 100644 --- a/signer/src/types/transaction_request.rs +++ b/signer/src/types/transaction_request.rs @@ -14,19 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! `TransactionRequest` type + use util::hash::Address; use util::numbers::U256; use types::bytes::Bytes; +/// Transaction request coming from RPC #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] pub struct TransactionRequest { + /// Sender pub from: Address, + /// Recipient pub to: Option
, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: Option, + /// Gas pub gas: Option, + /// Value of transaction in wei pub value: Option, + /// Additional data sent with transaction pub data: Option, + /// Transaction's nonce pub nonce: Option, } From b77fdcdd6876a2f05f1a0b63f6f9f50d7d5088ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 13:03:00 +0200 Subject: [PATCH 03/88] WebSockets server for signer --- Cargo.lock | 27 ++++++++ dapps/src/lib.rs | 6 +- parity/cli.rs | 7 ++ parity/main.rs | 24 ++++++- parity/setup_log.rs | 2 + parity/signer.rs | 67 +++++++++++++++++++ signer/Cargo.toml | 4 +- signer/src/lib.rs | 12 ++++ signer/src/types/bytes.rs | 4 +- signer/src/types/mod.rs | 2 + signer/src/types/mod.rs.in | 2 - signer/src/ws_server.rs | 128 +++++++++++++++++++++++++++++++++++++ 12 files changed, 275 insertions(+), 10 deletions(-) create mode 100644 parity/signer.rs create mode 100644 signer/src/ws_server.rs diff --git a/Cargo.lock b/Cargo.lock index 8379e101e..66df9192a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,11 @@ name = "bloomchain" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytes" version = "0.3.0" @@ -356,6 +361,7 @@ dependencies = [ "serde_codegen 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ws 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1167,6 +1173,14 @@ dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha1" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sha3" version = "0.1.0" @@ -1411,6 +1425,19 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ws" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index c6e75072d..e0676881f 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -34,9 +34,9 @@ //! let io = IoHandler::new(); //! io.add_method("say_hello", SayHello); //! let _server = Server::start_unsecure_http( -//! &"127.0.0.1:3030".parse().unwrap(), -//! Arc::new(io) -//! ); +//! &"127.0.0.1:3030".parse().unwrap(), +//! Arc::new(io) +//! ); //! } //! ``` //! diff --git a/parity/cli.rs b/parity/cli.rs index 4bb74f188..60b622bf7 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -97,6 +97,11 @@ API and Console Options: --dapps-pass PASSWORD Specify password for Dapps server. Use only in conjunction with --dapps-user. + --signer Enable Trusted Signer WebSocket endpoint used by + System UIs. + --signer-port PORT Specify the port of Trusted Signer server + [default: 8180]. + Sealing/Mining Options: --force-sealing Force the node to author new blocks as if it were always sealing/mining. @@ -234,6 +239,8 @@ pub struct Args { pub flag_dapps_interface: String, pub flag_dapps_user: Option, pub flag_dapps_pass: Option, + pub flag_signer: bool, + pub flag_signer_port: u16, pub flag_force_sealing: bool, pub flag_author: String, pub flag_usd_per_tx: String, diff --git a/parity/main.rs b/parity/main.rs index e87828f64..1e9ab33f5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,6 +50,11 @@ extern crate ethcore_rpc; #[cfg(feature = "dapps")] extern crate ethcore_dapps; +#[cfg(feature = "ethcore-signer")] +extern crate ethcore_signer; + + + #[macro_use] mod die; mod price_info; @@ -63,6 +68,7 @@ mod io_handler; mod cli; mod configuration; mod migration; +mod signer; use std::io::{Write, Read, BufReader, BufRead}; use std::ops::Deref; @@ -89,6 +95,7 @@ use informant::Informant; use die::*; use cli::print_version; use rpc::RpcServer; +use signer::SignerServer; use dapps::WebappServer; use io_handler::ClientIoHandler; use configuration::Configuration; @@ -231,6 +238,14 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) settings: network_settings.clone(), }); + // Set up a signer + let signer_server = signer::start(signer::Configuration { + enabled: conf.args.flag_signer, + port: conf.args.flag_signer_port, + }, signer::Dependencies { + panic_handler: panic_handler.clone(), + }); + // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), @@ -241,7 +256,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) service.io().register_handler(io_handler).expect("Error registering IO handler"); // Handle exit - wait_for_exit(panic_handler, rpc_server, dapps_server); + wait_for_exit(panic_handler, rpc_server, dapps_server, signer_server); } fn flush_stdout() { @@ -453,7 +468,12 @@ fn execute_account_cli(conf: Configuration) { } } -fn wait_for_exit(panic_handler: Arc, _rpc_server: Option, _dapps_server: Option) { +fn wait_for_exit( + panic_handler: Arc, + _rpc_server: Option, + _dapps_server: Option, + _signer_server: Option + ) { let exit = Arc::new(Condvar::new()); // Handle possible exits diff --git a/parity/setup_log.rs b/parity/setup_log.rs index 0fbc76fb3..4ed153fc2 100644 --- a/parity/setup_log.rs +++ b/parity/setup_log.rs @@ -27,6 +27,8 @@ pub fn setup_log(init: &Option) -> Arc { let mut levels = String::new(); let mut builder = LogBuilder::new(); + // Disable ws info logging by default. + builder.filter(Some("ws"), LogLevelFilter::Warn); builder.filter(None, LogLevelFilter::Info); if env::var("RUST_LOG").is_ok() { diff --git a/parity/signer.rs b/parity/signer.rs new file mode 100644 index 000000000..e7f7a9cb9 --- /dev/null +++ b/parity/signer.rs @@ -0,0 +1,67 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use util::panics::{PanicHandler, ForwardPanic}; +use die::*; + +#[cfg(feature = "ethcore-signer")] +use ethcore_signer as signer; +#[cfg(feature = "ethcore-signer")] +pub use ethcore_signer::Server as SignerServer; +#[cfg(not(feature = "ethcore-signer"))] +pub struct SignerServer; + +pub struct Configuration { + pub enabled: bool, + pub port: u16, +} + +pub struct Dependencies { + pub panic_handler: Arc, +} + +#[cfg(feature = "ethcore-signer")] +pub fn start(conf: Configuration, deps: Dependencies) -> Option { + if !conf.enabled { + return None; + } + + let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| die!("Invalid port specified: {}", conf.port)); + let start_result = signer::Server::start(addr); + + match start_result { + Err(signer::ServerError::IoError(err)) => die_with_io_error("Trusted Signer", err), + Err(e) => die!("Trusted Signer: {:?}", e), + Ok(server) => { + deps.panic_handler.forward_from(&server); + Some(server) + }, + } +} + +#[cfg(not(feature = "ethcore-signer"))] +pub fn start(conf: Configuration) -> !{ + if !conf.enabled { + return None; + } + + die!("Your Parity version has been compiled without Trusted Signer support.") +} + + + + diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 0d7f562ab..be77a3fd9 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -15,11 +15,13 @@ syntex = "^0.32.0" [dependencies] serde = "0.7.0" serde_json = "0.7.0" -serde_macros = { version = "0.7.0", optional = true } rustc-serialize = "0.3" ethcore-util = { path = "../util" } log = "0.3" env_logger = "0.3" +ws = "0.4.7" + +serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.69", optional = true} [features] diff --git a/signer/src/lib.rs b/signer/src/lib.rs index d8e7f63ec..13f8d2fa6 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -30,7 +30,15 @@ //! and their responsibility is to confirm (or confirm and sign) //! the transaction for you. //! +//! ``` +//! extern crate ethcore_signer; //! +//! use ethcore_signer::Server; +//! +//! fn main() { +//! let _server = Server::start("127.0.0.1:8084".parse().unwrap()); +//! } +//! ``` #[macro_use] extern crate log; @@ -41,10 +49,14 @@ extern crate serde_json; extern crate rustc_serialize; extern crate ethcore_util as util; +extern crate ws; mod signing_queue; +mod ws_server; pub mod types; +pub use ws_server::*; + #[cfg(test)] mod tests { #[test] diff --git a/signer/src/types/bytes.rs b/signer/src/types/bytes.rs index d8896f849..503927676 100644 --- a/signer/src/types/bytes.rs +++ b/signer/src/types/bytes.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Serializable wrapper around vector of bytes + use rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; use serde::de::Visitor; use util::common::FromHex; -///! Serializable wrapper around vector of bytes - /// Wrapper structure around vector of bytes. #[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] pub struct Bytes(pub Vec); diff --git a/signer/src/types/mod.rs b/signer/src/types/mod.rs index adf9be071..d5e15046a 100644 --- a/signer/src/types/mod.rs +++ b/signer/src/types/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Reusable types with JSON Serialization. + #[cfg(feature = "serde_macros")] include!("mod.rs.in"); diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in index 8e9befa4f..986e3d6e2 100644 --- a/signer/src/types/mod.rs.in +++ b/signer/src/types/mod.rs.in @@ -14,7 +14,5 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -///! Reusable types with JSON Serialization. - pub mod transaction_request; pub mod bytes; diff --git a/signer/src/ws_server.rs b/signer/src/ws_server.rs new file mode 100644 index 000000000..9be392e69 --- /dev/null +++ b/signer/src/ws_server.rs @@ -0,0 +1,128 @@ +// 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 . + +//! `WebSockets` server. + +use ws; +use std; +use std::thread; +use std::ops::Drop; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::net::SocketAddr; +use util::panics::{PanicHandler, OnPanicListener, MayPanic}; + +/// Signer startup error +#[derive(Debug)] +pub enum ServerError { + /// Wrapped `std::io::Error` + IoError(std::io::Error), + /// Other `ws-rs` error + Other(ws::Error) +} + +impl From for ServerError { + fn from(err: ws::Error) -> Self { + match err.kind { + ws::ErrorKind::Io(e) => ServerError::IoError(e), + _ => ServerError::Other(err), + } + } +} + +/// `WebSockets` server implementation. +pub struct Server { + handle: Option>>, + broadcaster: ws::Sender, + panic_handler: Arc, +} + +impl Server { + /// Starts a new `WebSocket` server in separate thread. + /// Returns a `Server` handle which closes the server when droped. + pub fn start(addr: SocketAddr) -> Result { + let config = { + let mut config = ws::Settings::default(); + config.max_connections = 5; + config.method_strict = true; + config + }; + + // Create WebSocket + let session_id = Arc::new(AtomicUsize::new(1)); + let ws = try!(ws::Builder::new().with_settings(config).build(Factory { + session_id: session_id, + })); + + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); + let broadcaster = ws.broadcaster(); + // Spawn a thread with event loop + let handle = thread::spawn(move || { + ph.catch_panic(move || { + ws.listen(addr).unwrap() + }).unwrap() + }); + + // Return a handle + Ok(Server { + handle: Some(handle), + broadcaster: broadcaster, + panic_handler: panic_handler, + }) + } +} + +impl MayPanic for Server { + fn on_panic(&self, closure: F) where F: OnPanicListener { + self.panic_handler.on_panic(closure); + } +} + +impl Drop for Server { + fn drop(&mut self) { + self.broadcaster.shutdown().expect("WsServer should close nicely."); + self.handle.take().unwrap().join().unwrap(); + } +} + +struct Session { + id: usize, + out: ws::Sender, +} + +impl ws::Handler for Session { + fn on_open(&mut self, _shake: ws::Handshake) -> ws::Result<()> { + try!(self.out.send(format!("Hello client no: {}. We are not implemented yet.", self.id))); + try!(self.out.close(ws::CloseCode::Normal)); + Ok(()) + } +} + +struct Factory { + session_id: Arc, +} + +impl ws::Factory for Factory { + type Handler = Session; + + fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler { + Session { + id: self.session_id.fetch_add(1, Ordering::SeqCst), + out: sender, + } + } +} From e2db4972be2f136182c9f2f444a8bb44b4e36188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 13:04:54 +0200 Subject: [PATCH 04/88] Removing TODO --- rpc/src/v1/types/mod.rs.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 9b56221b5..9d7fc882a 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -// TODO import signer types - mod block; mod block_number; mod filter; From d0ae713b29c112ce320d15f70d88019f5bac1a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 13:05:54 +0200 Subject: [PATCH 05/88] Shortening the syntax --- signer/src/types/bytes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/src/types/bytes.rs b/signer/src/types/bytes.rs index 503927676..76d84d0dd 100644 --- a/signer/src/types/bytes.rs +++ b/signer/src/types/bytes.rs @@ -32,7 +32,7 @@ impl Bytes { } /// Convert back to vector pub fn to_vec(self) -> Vec { - let Bytes(x) = self; x + self.0 } } From cf19e3866366451b2e96beb2f01e35c89f9e2ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 15:46:07 +0200 Subject: [PATCH 06/88] Exposing types from RPC --- Cargo.lock | 2 +- rpc/Cargo.toml | 1 - rpc/src/lib.rs | 1 - rpc/src/v1/mod.rs | 4 +-- rpc/src/v1/types/block.rs | 23 ++++++++++++ rpc/src/v1/types/block_number.rs | 4 +++ {signer/src => rpc/src/v1}/types/bytes.rs | 0 rpc/src/v1/types/call_request.rs | 8 +++++ rpc/src/v1/types/filter.rs | 11 ++++++ rpc/src/v1/types/index.rs | 1 + rpc/src/v1/types/log.rs | 10 ++++++ rpc/src/v1/types/mod.rs | 2 ++ rpc/src/v1/types/mod.rs.in | 6 ++-- rpc/src/v1/types/optionals.rs | 3 ++ rpc/src/v1/types/receipt.rs | 9 +++++ rpc/src/v1/types/sync.rs | 7 ++++ rpc/src/v1/types/trace.rs | 35 +++++++++++++++++++ rpc/src/v1/types/trace_filter.rs | 5 +++ rpc/src/v1/types/transaction.rs | 12 +++++++ .../src/v1}/types/transaction_request.rs | 2 +- signer/Cargo.toml | 3 +- signer/src/lib.rs | 2 +- signer/src/signing_queue.rs | 4 +-- signer/src/types/mod.rs.in | 11 ++++-- signer/src/ws_server.rs | 4 +-- 25 files changed, 154 insertions(+), 16 deletions(-) rename {signer/src => rpc/src/v1}/types/bytes.rs (100%) rename {signer/src => rpc/src/v1}/types/transaction_request.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 66df9192a..6298ef7ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,7 +331,6 @@ dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore 1.2.0", - "ethcore-signer 1.2.0", "ethcore-util 1.2.0", "ethminer 1.2.0", "ethsync 1.2.0", @@ -353,6 +352,7 @@ version = "1.2.0" dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-rpc 1.2.0", "ethcore-util 1.2.0", "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)", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c8bfa0485..2cdbb0a2b 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,7 +19,6 @@ ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethminer = { path = "../miner" } -ethcore-signer = { path = "../signer" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index ae824adf2..7d9818615 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -27,7 +27,6 @@ extern crate serde_json; extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_util as util; -extern crate ethcore_signer as signer; extern crate ethcore; extern crate ethsync; extern crate ethminer; diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index f3bb450f3..b1ab256c0 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -18,12 +18,12 @@ //! //! Compliant with ethereum rpc. -pub mod traits; mod impls; -mod types; mod helpers; +pub mod traits; pub mod tests; +pub mod types; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc}; pub use self::impls::*; diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index c38949c08..5810c85e5 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -18,9 +18,12 @@ use serde::{Serialize, Serializer}; use util::numbers::*; use v1::types::{Bytes, Transaction, OptionalValue}; +/// Block Transactions #[derive(Debug)] pub enum BlockTransactions { + /// Only hashes Hashes(Vec), + /// Full transactions Full(Vec) } @@ -34,38 +37,58 @@ impl Serialize for BlockTransactions { } } +/// Block representation #[derive(Debug, Serialize)] pub struct Block { + /// Hash of the block pub hash: OptionalValue, + /// Hash of the parent #[serde(rename="parentHash")] pub parent_hash: H256, + /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, + /// Authors address pub author: Address, // TODO: get rid of this one + /// ? pub miner: Address, + /// State root hash #[serde(rename="stateRoot")] pub state_root: H256, + /// Transactions root hash #[serde(rename="transactionsRoot")] pub transactions_root: H256, + /// Transactions receipts root hash #[serde(rename="receiptsRoot")] pub receipts_root: H256, + /// Block number pub number: OptionalValue, + /// Gas Used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Gas Limit #[serde(rename="gasLimit")] pub gas_limit: U256, + /// Extra data #[serde(rename="extraData")] pub extra_data: Bytes, + /// Logs bloom #[serde(rename="logsBloom")] pub logs_bloom: H2048, + /// Timestamp pub timestamp: U256, + /// Difficulty pub difficulty: U256, + /// Total difficulty #[serde(rename="totalDifficulty")] pub total_difficulty: U256, + /// Seal fields #[serde(rename="sealFields")] pub seal_fields: Vec, + /// Uncles' hashes pub uncles: Vec, + /// Transactions pub transactions: BlockTransactions } diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index 071486afd..e2d150c66 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -21,9 +21,13 @@ use ethcore::client::BlockID; /// Represents rpc api block number param. #[derive(Debug, PartialEq, Clone)] pub enum BlockNumber { + /// Number Num(u64), + /// Latest block Latest, + /// Earliest block (genesis) Earliest, + /// Pending block (being mined) Pending } diff --git a/signer/src/types/bytes.rs b/rpc/src/v1/types/bytes.rs similarity index 100% rename from signer/src/types/bytes.rs rename to rpc/src/v1/types/bytes.rs diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs index 045b1cd9b..50ebbd1f0 100644 --- a/rpc/src/v1/types/call_request.rs +++ b/rpc/src/v1/types/call_request.rs @@ -18,15 +18,23 @@ use util::hash::Address; use util::numbers::U256; use v1::types::Bytes; +/// Call request #[derive(Debug, Default, PartialEq, Deserialize)] pub struct CallRequest { + /// From pub from: Option
, + /// To pub to: Option
, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: Option, + /// Gas pub gas: Option, + /// Value pub value: Option, + /// Data pub data: Option, + /// Nonce pub nonce: Option, } diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index e50ec9c32..77a3f0500 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -22,10 +22,14 @@ use v1::types::BlockNumber; use ethcore::filter::Filter as EthFilter; use ethcore::client::BlockID; +/// Variadic value #[derive(Debug, PartialEq, Clone)] pub enum VariadicValue where T: Deserialize { + /// Single Single(T), + /// List Multiple(Vec), + /// None Null, } @@ -44,17 +48,24 @@ impl Deserialize for VariadicValue where T: Deserialize { } } +/// Filter Address pub type FilterAddress = VariadicValue
; +/// Topic pub type Topic = VariadicValue; +/// Filter #[derive(Debug, PartialEq, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Filter { + /// From Block #[serde(rename="fromBlock")] pub from_block: Option, + /// To Block #[serde(rename="toBlock")] pub to_block: Option, + /// Address pub address: Option, + /// Topics pub topics: Option>, } diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index e7cbbd255..d7b17aea2 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -22,6 +22,7 @@ use serde::de::Visitor; pub struct Index(usize); impl Index { + /// Convert to usize pub fn value(&self) -> usize { self.0 } diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 426ca68f1..72a482d1b 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -18,21 +18,31 @@ use util::numbers::*; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use v1::types::Bytes; +/// Log #[derive(Debug, Serialize, PartialEq, Eq, Hash, Clone)] pub struct Log { + /// Address pub address: Address, + /// Topics pub topics: Vec, + /// Data pub data: Bytes, + /// Block Hash #[serde(rename="blockHash")] pub block_hash: Option, + /// Block Number #[serde(rename="blockNumber")] pub block_number: Option, + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: Option, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: Option, + /// Log Index #[serde(rename="logIndex")] pub log_index: Option, + /// Log Type #[serde(rename="type")] pub log_type: String, } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index adf9be071..c1bc34407 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Structures used in RPC communication + #[cfg(feature = "serde_macros")] include!("mod.rs.in"); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 9d7fc882a..824a061ef 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +mod bytes; mod block; mod block_number; mod filter; @@ -22,13 +23,13 @@ mod log; mod optionals; mod sync; mod transaction; +mod transaction_request; mod call_request; mod receipt; mod trace; mod trace_filter; -pub use signer::types::bytes::Bytes; -pub use signer::types::transaction_request::TransactionRequest; +pub use self::bytes::Bytes; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::filter::Filter; @@ -37,6 +38,7 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; +pub use self::transaction_request::TransactionRequest; pub use self::call_request::CallRequest; pub use self::receipt::Receipt; pub use self::trace::Trace; diff --git a/rpc/src/v1/types/optionals.rs b/rpc/src/v1/types/optionals.rs index 5db272251..2ed272ade 100644 --- a/rpc/src/v1/types/optionals.rs +++ b/rpc/src/v1/types/optionals.rs @@ -17,9 +17,12 @@ use serde::{Serialize, Serializer}; use serde_json::Value; +/// Optional value #[derive(Debug)] pub enum OptionalValue where T: Serialize { + /// Some Value(T), + /// None Null } diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index 51d914e1a..32a7f5945 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -19,22 +19,31 @@ use util::hash::{Address, H256}; use v1::types::Log; use ethcore::receipt::LocalizedReceipt; +/// Receipt #[derive(Debug, Serialize)] pub struct Receipt { + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: H256, + /// Transaction index #[serde(rename="transactionIndex")] pub transaction_index: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: H256, + /// Block number #[serde(rename="blockNumber")] pub block_number: U256, + /// Cumulative gas used #[serde(rename="cumulativeGasUsed")] pub cumulative_gas_used: U256, + /// Gas used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Contract address #[serde(rename="contractAddress")] pub contract_address: Option
, + /// Logs pub logs: Vec, } diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index c0e480140..6d750425e 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -17,19 +17,26 @@ use serde::{Serialize, Serializer}; use util::numbers::*; +/// Sync info #[derive(Default, Debug, Serialize, PartialEq)] pub struct SyncInfo { + /// Starting block #[serde(rename="startingBlock")] pub starting_block: U256, + /// Current block #[serde(rename="currentBlock")] pub current_block: U256, + /// Highest block seen so far #[serde(rename="highestBlock")] pub highest_block: U256, } +/// Sync status #[derive(Debug, PartialEq)] pub enum SyncStatus { + /// Info when syncing Info(SyncInfo), + /// Not syncing None } diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index 4cd1ac408..6ea58543a 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -19,11 +19,16 @@ use ethcore::trace::trace; use ethcore::trace::LocalizedTrace; use v1::types::Bytes; +/// Create response #[derive(Debug, Serialize)] pub struct Create { + /// Sender from: Address, + /// Value value: U256, + /// Gas gas: U256, + /// Initialization code init: Bytes, } @@ -38,12 +43,18 @@ impl From for Create { } } +/// Call response #[derive(Debug, Serialize)] pub struct Call { + /// Sender from: Address, + /// Recipient to: Address, + /// Transfered Value value: U256, + /// Gas gas: U256, + /// Input data input: Bytes, } @@ -59,10 +70,13 @@ impl From for Call { } } +/// Action #[derive(Debug, Serialize)] pub enum Action { + /// Call #[serde(rename="call")] Call(Call), + /// Create #[serde(rename="create")] Create(Create), } @@ -76,10 +90,13 @@ impl From for Action { } } +/// Call Result #[derive(Debug, Serialize)] pub struct CallResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Output bytes output: Bytes, } @@ -92,11 +109,15 @@ impl From for CallResult { } } +/// Craete Result #[derive(Debug, Serialize)] pub struct CreateResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Code code: Bytes, + /// Assigned address address: Address, } @@ -110,14 +131,19 @@ impl From for CreateResult { } } +/// Response #[derive(Debug, Serialize)] pub enum Res { + /// Call #[serde(rename="call")] Call(CallResult), + /// Create #[serde(rename="create")] Create(CreateResult), + /// Call failure #[serde(rename="failedCall")] FailedCall, + /// Creation failure #[serde(rename="failedCreate")] FailedCreate, } @@ -133,19 +159,28 @@ impl From for Res { } } +/// Trace #[derive(Debug, Serialize)] pub struct Trace { + /// Action action: Action, + /// Result result: Res, + /// Trace address #[serde(rename="traceAddress")] trace_address: Vec, + /// Subtraces subtraces: U256, + /// Transaction position #[serde(rename="transactionPosition")] transaction_position: U256, + /// Transaction hash #[serde(rename="transactionHash")] transaction_hash: H256, + /// Block Number #[serde(rename="blockNumber")] block_number: U256, + /// Block Hash #[serde(rename="blockHash")] block_hash: H256, } diff --git a/rpc/src/v1/types/trace_filter.rs b/rpc/src/v1/types/trace_filter.rs index 3d45f4c79..ee2f231f0 100644 --- a/rpc/src/v1/types/trace_filter.rs +++ b/rpc/src/v1/types/trace_filter.rs @@ -21,14 +21,19 @@ use ethcore::client::BlockID; use ethcore::client; use super::BlockNumber; +/// Trace filter #[derive(Debug, PartialEq, Deserialize)] pub struct TraceFilter { + /// From block #[serde(rename="fromBlock")] pub from_block: Option, + /// To block #[serde(rename="toBlock")] pub to_block: Option, + /// From address #[serde(rename="fromAddress")] pub from_address: Option>, + /// To address #[serde(rename="toAddress")] pub to_address: Option>, } diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 8a46d5e15..1c9a41084 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -18,22 +18,34 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction}; use v1::types::{Bytes, OptionalValue}; +/// Transaction #[derive(Debug, Default, Serialize)] pub struct Transaction { + /// Hash pub hash: H256, + /// Nonce pub nonce: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: OptionalValue, + /// Block number #[serde(rename="blockNumber")] pub block_number: OptionalValue, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: OptionalValue, + /// Sender pub from: Address, + /// Recipient pub to: OptionalValue
, + /// Transfered value pub value: U256, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: U256, + /// Gas pub gas: U256, + /// Data pub input: Bytes } diff --git a/signer/src/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs similarity index 99% rename from signer/src/types/transaction_request.rs rename to rpc/src/v1/types/transaction_request.rs index 83840515b..2fc806912 100644 --- a/signer/src/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -18,7 +18,7 @@ use util::hash::Address; use util::numbers::U256; -use types::bytes::Bytes; +use v1::types::bytes::Bytes; /// Transaction request coming from RPC #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] diff --git a/signer/Cargo.toml b/signer/Cargo.toml index be77a3fd9..59c7f90b2 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -16,10 +16,11 @@ syntex = "^0.32.0" serde = "0.7.0" serde_json = "0.7.0" rustc-serialize = "0.3" -ethcore-util = { path = "../util" } log = "0.3" env_logger = "0.3" ws = "0.4.7" +ethcore-util = { path = "../util" } +ethcore-rpc = { path = "../rpc" } serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.69", optional = true} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 13f8d2fa6..4317338e0 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -49,11 +49,11 @@ extern crate serde_json; extern crate rustc_serialize; extern crate ethcore_util as util; +extern crate ethcore_rpc as rpc; extern crate ws; mod signing_queue; mod ws_server; -pub mod types; pub use ws_server::*; diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs index 7758f5df3..d320d2375 100644 --- a/signer/src/signing_queue.rs +++ b/signer/src/signing_queue.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::collections::HashSet; -use types::transaction_request::TransactionRequest; +use rpc::v1::types::TransactionRequest; pub trait SigningQueue { fn add_request(&mut self, transaction: TransactionRequest); @@ -45,7 +45,7 @@ mod test { use std::collections::HashSet; use util::hash::Address; use util::numbers::U256; - use types::transaction_request::TransactionRequest; + use rpc::v1::types::transaction_request::TransactionRequest; use super::*; #[test] diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in index 986e3d6e2..a59f81ece 100644 --- a/signer/src/types/mod.rs.in +++ b/signer/src/types/mod.rs.in @@ -14,5 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -pub mod transaction_request; -pub mod bytes; + + + + + + + + +// TODO [ToDr] Types are empty for now. But they are about to come. diff --git a/signer/src/ws_server.rs b/signer/src/ws_server.rs index 9be392e69..d2ab02d66 100644 --- a/signer/src/ws_server.rs +++ b/signer/src/ws_server.rs @@ -31,14 +31,14 @@ pub enum ServerError { /// Wrapped `std::io::Error` IoError(std::io::Error), /// Other `ws-rs` error - Other(ws::Error) + WebSocket(ws::Error) } impl From for ServerError { fn from(err: ws::Error) -> Self { match err.kind { ws::ErrorKind::Io(e) => ServerError::IoError(e), - _ => ServerError::Other(err), + _ => ServerError::WebSocket(err), } } } From c4e2f650513f70f4e2f80592e8e191882ad84931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 17:46:15 +0200 Subject: [PATCH 07/88] Exposing RPC over websockets --- Cargo.lock | 1 + parity/main.rs | 5 ++ parity/signer.rs | 47 ++++++++---- rpc/src/v1/types/transaction_request.rs | 2 +- signer/Cargo.toml | 1 + signer/src/lib.rs | 1 + signer/src/signing_queue.rs | 2 +- signer/src/{ws_server.rs => ws_server/mod.rs} | 73 ++++++++++--------- signer/src/ws_server/session.rs | 59 +++++++++++++++ 9 files changed, 140 insertions(+), 51 deletions(-) rename signer/src/{ws_server.rs => ws_server/mod.rs} (70%) create mode 100644 signer/src/ws_server/session.rs diff --git a/Cargo.lock b/Cargo.lock index 6298ef7ea..7950ecc4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,6 +354,7 @@ dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-rpc 1.2.0", "ethcore-util 1.2.0", + "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/parity/main.rs b/parity/main.rs index 1e9ab33f5..61aa8ab21 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -244,6 +244,11 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) port: conf.args.flag_signer_port, }, signer::Dependencies { panic_handler: panic_handler.clone(), + client: client.clone(), + sync: sync.clone(), + secret_store: account_service.clone(), + miner: miner.clone(), + external_miner: external_miner.clone(), }); // Register IO handler diff --git a/parity/signer.rs b/parity/signer.rs index e7f7a9cb9..c4a540721 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -15,6 +15,10 @@ // along with Parity. If not, see . use std::sync::Arc; +use ethcore::client::Client; +use ethsync::EthSync; +use ethminer::{Miner, ExternalMiner}; +use util::keys::store::AccountService; use util::panics::{PanicHandler, ForwardPanic}; use die::*; @@ -32,36 +36,51 @@ pub struct Configuration { pub struct Dependencies { pub panic_handler: Arc, + pub client: Arc, + pub sync: Arc, + pub secret_store: Arc, + pub miner: Arc, + pub external_miner: Arc, +} + +pub fn start(conf: Configuration, deps: Dependencies) -> Option { + if !conf.enabled { + None + } else { + Some(do_start(conf, deps)) + } } #[cfg(feature = "ethcore-signer")] -pub fn start(conf: Configuration, deps: Dependencies) -> Option { - if !conf.enabled { - return None; - } +fn do_start(conf: Configuration, deps: Dependencies) -> SignerServer { + let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| { + die!("Invalid port specified: {}", conf.port) + }); - let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| die!("Invalid port specified: {}", conf.port)); - let start_result = signer::Server::start(addr); + let start_result = { + use ethcore_rpc::v1::*; + let server = signer::ServerBuilder::new(); + server.add_delegate(Web3Client::new().to_delegate()); + server.add_delegate(NetClient::new(&deps.sync).to_delegate()); + server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); + server.add_delegate(PersonalClient::new(&deps.secret_store).to_delegate()); + server.start(addr) + }; match start_result { Err(signer::ServerError::IoError(err)) => die_with_io_error("Trusted Signer", err), Err(e) => die!("Trusted Signer: {:?}", e), Ok(server) => { deps.panic_handler.forward_from(&server); - Some(server) + server }, } } #[cfg(not(feature = "ethcore-signer"))] -pub fn start(conf: Configuration) -> !{ - if !conf.enabled { - return None; - } - +fn do_start(conf: Configuration) -> ! { die!("Your Parity version has been compiled without Trusted Signer support.") } - - diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index 2fc806912..1b51e6b12 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -47,7 +47,7 @@ mod tests { use serde_json; use util::numbers::{U256}; use util::hash::Address; - use types::bytes::Bytes; + use v1::types::bytes::Bytes; use super::*; #[test] diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 59c7f90b2..51b1b1e8d 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -16,6 +16,7 @@ syntex = "^0.32.0" serde = "0.7.0" serde_json = "0.7.0" rustc-serialize = "0.3" +jsonrpc-core = "2.0" log = "0.3" env_logger = "0.3" ws = "0.4.7" diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 4317338e0..a39fe68f0 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -50,6 +50,7 @@ extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore_rpc as rpc; +extern crate jsonrpc_core; extern crate ws; mod signing_queue; diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs index d320d2375..611d467c2 100644 --- a/signer/src/signing_queue.rs +++ b/signer/src/signing_queue.rs @@ -45,7 +45,7 @@ mod test { use std::collections::HashSet; use util::hash::Address; use util::numbers::U256; - use rpc::v1::types::transaction_request::TransactionRequest; + use rpc::v1::types::TransactionRequest; use super::*; #[test] diff --git a/signer/src/ws_server.rs b/signer/src/ws_server/mod.rs similarity index 70% rename from signer/src/ws_server.rs rename to signer/src/ws_server/mod.rs index d2ab02d66..bb10bc5c1 100644 --- a/signer/src/ws_server.rs +++ b/signer/src/ws_server/mod.rs @@ -19,11 +19,14 @@ use ws; use std; use std::thread; +use std::default::Default; use std::ops::Drop; use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::net::SocketAddr; use util::panics::{PanicHandler, OnPanicListener, MayPanic}; +use jsonrpc_core::{IoHandler, IoDelegate}; + +mod session; /// Signer startup error #[derive(Debug)] @@ -43,9 +46,40 @@ impl From for ServerError { } } +/// Builder for `WebSockets` server +pub struct ServerBuilder { + handler: Arc, +} + +impl Default for ServerBuilder { + fn default() -> Self { + ServerBuilder::new() + } +} + +impl ServerBuilder { + /// Creates new `ServerBuilder` + pub fn new() -> Self { + ServerBuilder { + handler: Arc::new(IoHandler::new()) + } + } + + /// Adds rpc delegate + pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { + self.handler.add_delegate(delegate); + } + + /// Starts a new `WebSocket` server in separate thread. + /// Returns a `Server` handle which closes the server when droped. + pub fn start(self, addr: SocketAddr) -> Result { + Server::start(addr, self.handler) + } +} + /// `WebSockets` server implementation. pub struct Server { - handle: Option>>, + handle: Option>>, broadcaster: ws::Sender, panic_handler: Arc, } @@ -53,7 +87,7 @@ pub struct Server { impl Server { /// Starts a new `WebSocket` server in separate thread. /// Returns a `Server` handle which closes the server when droped. - pub fn start(addr: SocketAddr) -> Result { + pub fn start(addr: SocketAddr, handler: Arc) -> Result { let config = { let mut config = ws::Settings::default(); config.max_connections = 5; @@ -62,10 +96,7 @@ impl Server { }; // Create WebSocket - let session_id = Arc::new(AtomicUsize::new(1)); - let ws = try!(ws::Builder::new().with_settings(config).build(Factory { - session_id: session_id, - })); + let ws = try!(ws::Builder::new().with_settings(config).build(session::Factory::new(handler))); let panic_handler = PanicHandler::new_in_arc(); let ph = panic_handler.clone(); @@ -98,31 +129,3 @@ impl Drop for Server { self.handle.take().unwrap().join().unwrap(); } } - -struct Session { - id: usize, - out: ws::Sender, -} - -impl ws::Handler for Session { - fn on_open(&mut self, _shake: ws::Handshake) -> ws::Result<()> { - try!(self.out.send(format!("Hello client no: {}. We are not implemented yet.", self.id))); - try!(self.out.close(ws::CloseCode::Normal)); - Ok(()) - } -} - -struct Factory { - session_id: Arc, -} - -impl ws::Factory for Factory { - type Handler = Session; - - fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler { - Session { - id: self.session_id.fetch_add(1, Ordering::SeqCst), - out: sender, - } - } -} diff --git a/signer/src/ws_server/session.rs b/signer/src/ws_server/session.rs new file mode 100644 index 000000000..258e05d5b --- /dev/null +++ b/signer/src/ws_server/session.rs @@ -0,0 +1,59 @@ +// 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 . + +//! Session handlers factory. + +use ws; +use std::sync::Arc; +use jsonrpc_core::IoHandler; + +pub struct Session { + out: ws::Sender, + handler: Arc, +} + +impl ws::Handler for Session { + fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> { + let req = try!(msg.as_text()); + match self.handler.handle_request(req) { + Some(res) => self.out.send(res), + None => Ok(()), + } + } +} + +pub struct Factory { + handler: Arc, +} + +impl Factory { + pub fn new(handler: Arc) -> Self { + Factory { + handler: handler, + } + } +} + +impl ws::Factory for Factory { + type Handler = Session; + + fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler { + Session { + out: sender, + handler: self.handler.clone(), + } + } +} From 58039fb42072ea3310e2286ab0d84a6db1442b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 17:56:25 +0200 Subject: [PATCH 08/88] Fixing few clippy warnings --- ethcore/src/blooms/group_position.rs | 2 +- ethcore/src/trace/db.rs | 2 +- parity/migration.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/blooms/group_position.rs b/ethcore/src/blooms/group_position.rs index f698ca4e5..3a6cc8e83 100644 --- a/ethcore/src/blooms/group_position.rs +++ b/ethcore/src/blooms/group_position.rs @@ -17,7 +17,7 @@ use bloomchain::group as bc; use util::HeapSizeOf; -/// Represents BloomGroup position in database. +/// Represents `BloomGroup` position in database. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct GroupPosition { /// Bloom level. diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index d540f1b6e..e40fa1b00 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -54,7 +54,7 @@ impl Key for H256 { } } -/// Wrapper around blooms::GroupPosition so it could be +/// Wrapper around `blooms::GroupPosition` so it could be /// uniquely identified in the database. #[derive(Debug, PartialEq, Eq, Hash, Clone)] struct TraceGroupPosition(blooms::GroupPosition); diff --git a/parity/migration.rs b/parity/migration.rs index d41c502cc..acfd32ffd 100644 --- a/parity/migration.rs +++ b/parity/migration.rs @@ -73,7 +73,7 @@ fn version_file_path(path: &PathBuf) -> PathBuf { } /// Reads current database version from the file at given path. -/// If the file does not exist returns DEFAULT_VERSION. +/// If the file does not exist returns `DEFAULT_VERSION`. fn current_version(path: &PathBuf) -> Result { match File::open(version_file_path(path)) { Err(ref err) if err.kind() == ErrorKind::NotFound => Ok(DEFAULT_VERSION), From 56b020987e550ea52f255b37cddaec52fb8c8487 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 12:21:40 +0200 Subject: [PATCH 09/88] refine tests for call deserialization --- json/src/bytes.rs | 9 +++++++++ json/src/vm/call.rs | 37 ++++++++++++++++++++++++++++++++++--- rpc/src/v1/impls/ethcore.rs | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 812b109f7..18dc73844 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -19,6 +19,7 @@ use rustc_serialize::hex::FromHex; use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; +use std::ops::Deref; /// Lenient bytes json deserialization for test json files. #[derive(Default, Debug, PartialEq, Clone)] @@ -30,6 +31,14 @@ impl Into> for Bytes { } } +impl Deref for Bytes { + type Target = Vec; + + fn deref(&self) -> &Vec { + &self.0 + } +} + impl Deserialize for Bytes { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { diff --git a/json/src/vm/call.rs b/json/src/vm/call.rs index 2fe6265aa..1947fd25c 100644 --- a/json/src/vm/call.rs +++ b/json/src/vm/call.rs @@ -39,16 +39,47 @@ pub struct Call { mod tests { use serde_json; use vm::Call; + use util::numbers::U256; + use uint::Uint; + use util::hash::Address as Hash160; + use hash::Address; + use maybe::MaybeEmpty; + use std::str::FromStr; #[test] - fn call_deserialization() { + fn call_deserialization_empty_dest() { let s = r#"{ "data" : "0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff", "destination" : "", "gasLimit" : "0x1748766aa5", "value" : "0x00" }"#; - let _deserialized: Call = serde_json::from_str(s).unwrap(); - // TODO: validate all fields + let call: Call = serde_json::from_str(s).unwrap(); + + assert_eq!(&call.data[..], + &[0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, + 0x88, 0x88, 0x99, 0x99, 0x00, 0x00, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, + 0xee, 0xee, 0xff, 0xff]); + + assert_eq!(call.destination, MaybeEmpty::None); + assert_eq!(call.gas_limit, Uint(U256::from(0x1748766aa5u64))); + assert_eq!(call.value, Uint(U256::from(0))); + } + + #[test] + fn call_deserialization_full_dest() { + let s = r#"{ + "data" : "0x1234", + "destination" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c", + "gasLimit" : "0x1748766aa5", + "value" : "0x00" + }"#; + + let call: Call = serde_json::from_str(s).unwrap(); + + assert_eq!(&call.data[..], &[0x12, 0x34]); + assert_eq!(call.destination, MaybeEmpty::Some(Address(Hash160::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c").unwrap()))); + assert_eq!(call.gas_limit, Uint(U256::from(0x1748766aa5u64))); + assert_eq!(call.value, Uint(U256::from(0))); } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index de458a53f..f5d6f1fda 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -22,7 +22,7 @@ use std::sync::{Arc, Weak}; use std::ops::Deref; use std::collections::BTreeMap; use jsonrpc_core::*; -use ethminer::{MinerService}; +use ethminer::MinerService; use v1::traits::Ethcore; use v1::types::Bytes; From 152bb6f21b8abde53865ee7080ff2d55dc8d58dc Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 16:56:09 +0200 Subject: [PATCH 10/88] create integration test harness for eth RPC API --- rpc/Cargo.toml | 4 + rpc/src/lib.rs | 5 ++ rpc/src/v1/tests/eth.rs | 0 rpc/src/v1/tests/helpers/sync_provider.rs | 4 +- rpc/src/v1/tests/integration/eth.rs | 100 ++++++++++++++++++++++ rpc/src/v1/tests/integration/mod.rs | 21 +++++ rpc/src/v1/tests/mod.rs | 2 +- 7 files changed, 133 insertions(+), 3 deletions(-) delete mode 100644 rpc/src/v1/tests/eth.rs create mode 100644 rpc/src/v1/tests/integration/eth.rs create mode 100644 rpc/src/v1/tests/integration/mod.rs diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2cdbb0a2b..23fef5d06 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -29,6 +29,10 @@ json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } serde_codegen = { version = "0.7.0", optional = true } syntex = "^0.32.0" +[dev-dependencies] +ethjson = { path = "../json" } +ethcore-devtools = { path = "../devtools" } + [features] default = ["serde_codegen"] nightly = ["serde_macros"] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7d9818615..24d58819c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,6 +33,11 @@ extern crate ethminer; extern crate transient_hashmap; extern crate json_ipc_server as ipc; +#[cfg(test)] +extern crate ethjson; +#[cfg(test)] +extern crate ethcore_devtools as devtools; + use std::sync::Arc; use std::net::SocketAddr; use self::jsonrpc_core::{IoHandler, IoDelegate}; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index fc81586dd..114b5b08f 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -16,9 +16,9 @@ //! Test implementation of SyncProvider. -use util::{U256}; +use util::U256; use ethsync::{SyncProvider, SyncStatus, SyncState}; -use std::sync::{RwLock}; +use std::sync::RwLock; /// TestSyncProvider config. pub struct Config { diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs new file mode 100644 index 000000000..d402f2b08 --- /dev/null +++ b/rpc/src/v1/tests/integration/eth.rs @@ -0,0 +1,100 @@ +// Copyright 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 . + +//! rpc integration tests. +use std::collections::HashMap; +use std::sync::Arc; + +use ethjson::blockchain::test::Test; +use ethcore::client::{BlockChainClient, Client, ClientConfig}; +use ethcore::spec::Genesis; +use ethcore::block::Block; +use ethcore::ethereum; +use ethminer::ExternalMiner; +use devtools::RandomTempPath; +use util::io::IoChannel; +use util::hash::{Address, FixedHash}; +use util::numbers::U256; +use util::keys::{TestAccount, TestAccountProvider}; +use jsonrpc_core::IoHandler; + +use v1::traits::eth::Eth; +use v1::impls::EthClient; +use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; + +use super::RPC_CHAIN; + +#[test] +fn harness_works() { + eth_harness(|_| {}); +} + +fn account_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + network_id: U256::from(3), + num_peers: 120, + })) +} + +fn miner_service() -> Arc { + Arc::new(TestMinerService::default()) +} + +// this harness will create a handler which tests can send specially-crafted +// JSONRPC requests to. +fn eth_harness(mut cb: F) -> U + where F: FnMut(&IoHandler) -> U { + let chains = Test::load(RPC_CHAIN).unwrap(); + let chain = chains.into_iter().next().unwrap().1; + let genesis = Genesis::from(chain.genesis()); + let mut spec = ethereum::new_frontier_test(); + let state = chain.pre_state.clone().into(); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); + assert!(spec.is_state_root_valid()); + + let dir = RandomTempPath::new(); + let client = Client::new(ClientConfig::default(), spec, dir.as_path(), IoChannel::disconnected()).unwrap(); + let sync_provider = sync_provider(); + let miner_service = miner_service(); + let account_provider = account_provider(); + let external_miner = Arc::new(ExternalMiner::default()); + + for b in &chain.blocks_rlp() { + if Block::is_good(&b) { + let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); + } + } + + assert!(client.chain_info().best_block_hash == chain.best_block.into()); + + let eth_client = EthClient::new(&client, &sync_provider, &account_provider, + &miner_service, &external_miner); + + let handler = IoHandler::new(); + let delegate = eth_client.to_delegate(); + handler.add_delegate(delegate); + cb(&handler) +} diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs new file mode 100644 index 000000000..8a67d78dd --- /dev/null +++ b/rpc/src/v1/tests/integration/mod.rs @@ -0,0 +1,21 @@ +// Copyright 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 . + +//! Integration tests for the JSONRPC APIs + +mod eth; + +const RPC_CHAIN: &'static [u8] = include_bytes!("../../../../../ethcore/res/ethereum/tests/BlockchainTests/bcRPC_API_Test.json"); \ No newline at end of file diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index f5e7d1404..78a6a674f 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -5,4 +5,4 @@ pub mod helpers; #[cfg(test)] mod mocked; #[cfg(test)] -mod eth; \ No newline at end of file +mod integration; From d370a86b4325210820d269ed45377ac6580fc43a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 19:20:07 +0200 Subject: [PATCH 11/88] More flexible chain extraction, get_balance test --- rpc/src/v1/tests/integration/eth.rs | 42 ++++++++++++++++++++++------- rpc/src/v1/tests/integration/mod.rs | 35 ++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index d402f2b08..a2640203f 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -18,7 +18,6 @@ use std::collections::HashMap; use std::sync::Arc; -use ethjson::blockchain::test::Test; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; @@ -30,16 +29,43 @@ use util::hash::{Address, FixedHash}; use util::numbers::U256; use util::keys::{TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; +use ethjson::blockchain::BlockChain; use v1::traits::eth::Eth; use v1::impls::EthClient; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; -use super::RPC_CHAIN; - #[test] fn harness_works() { - eth_harness(|_| {}); + let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); + chain_harness(chain, |_| {}); +} + +#[test] +fn eth_get_balance() { + let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); + chain_harness(chain, |handler| { + // final account state + let req_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], + "id": 1 + }"#; + let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#; + assert_eq!(&handler.handle_request(req_latest).unwrap(), res_latest); + + // non-existant account + let req_new_acc = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], + "id": 3 + }"#; + + let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#; + assert_eq!(&handler.handle_request(req_new_acc).unwrap(), res_new_acc); + }); } fn account_provider() -> Arc { @@ -60,12 +86,10 @@ fn miner_service() -> Arc { Arc::new(TestMinerService::default()) } -// this harness will create a handler which tests can send specially-crafted -// JSONRPC requests to. -fn eth_harness(mut cb: F) -> U +// given a blockchain, this harness will create an EthClient wrapping it +// which tests can pass specially crafted requests to. +fn chain_harness(chain: BlockChain, mut cb: F) -> U where F: FnMut(&IoHandler) -> U { - let chains = Test::load(RPC_CHAIN).unwrap(); - let chain = chains.into_iter().next().unwrap().1; let genesis = Genesis::from(chain.genesis()); let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs index 8a67d78dd..4a845c074 100644 --- a/rpc/src/v1/tests/integration/mod.rs +++ b/rpc/src/v1/tests/integration/mod.rs @@ -16,6 +16,37 @@ //! Integration tests for the JSONRPC APIs -mod eth; +// extract a chain from the given JSON file, +// stored in ethcore/res/ethereum/tests/. +// +// usage: +// `extract_chain!("Folder/File")` will load Folder/File.json and extract +// the first block chain stored within. +// +// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and +// extract the chain with that name. This will panic if no chain by that name +// is found. +macro_rules! extract_chain { + ($file:expr, $name:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); + let mut chain = None; + for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { + if name == $name { + chain = Some(c); + break; + } + } + chain.unwrap() + }}; -const RPC_CHAIN: &'static [u8] = include_bytes!("../../../../../ethcore/res/ethereum/tests/BlockchainTests/bcRPC_API_Test.json"); \ No newline at end of file + ($file:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); + + ::ethjson::blockchain::Test::load(RAW_DATA) + .unwrap().into_iter().next().unwrap().1 + }}; +} + +mod eth; \ No newline at end of file From cf18c4bb0ac89f507deec985d1de69b3b9a8ad7f Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 12:30:55 +0200 Subject: [PATCH 12/88] make MinerService object-safe --- miner/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index e9ac7aba2..a1780efff 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -107,12 +107,12 @@ pub trait MinerService : Send + Sync { /// Imports transactions to transaction queue. fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> - where T: Fn(&Address) -> AccountDetails; + where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Imports own (node owner) transaction to queue. fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result - where T: Fn(&Address) -> AccountDetails; + where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Returns hashes of transactions currently in pending fn pending_transactions_hashes(&self) -> Vec; @@ -131,7 +131,8 @@ pub trait MinerService : Send + Sync { fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T; + fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option + where F: FnOnce(&ClosedBlock) -> T, Self: Sized; /// Query pending transactions for hash. fn transaction(&self, hash: &H256) -> Option; From 688790f13f5025d87c532b21109ae6fbdb07906b Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 12:44:27 +0200 Subject: [PATCH 13/88] re-export AccountProvider trait --- util/src/keys/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index 5d718affc..38fa51eca 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -21,4 +21,5 @@ pub mod store; mod geth_import; mod test_account_provider; +pub use self::store::AccountProvider; pub use self::test_account_provider::{TestAccount, TestAccountProvider}; From f67486e31f883926ac2af21867b2e8cb5388ea43 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:22:17 +0200 Subject: [PATCH 14/88] have miner service update the pending nonces on transaction import --- rpc/src/v1/tests/helpers/miner_service.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 5d57d5d61..36296613c 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -115,12 +115,18 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, _fetch_account: T) -> + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { // lets assume that all txs are valid self.imported_transactions.lock().unwrap().extend_from_slice(&transactions); + for transaction in &transactions { + if let Ok(ref sender) = transaction.sender() { + let nonce = self.last_nonce(sender).unwrap_or(fetch_account(sender).nonce); + self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); + } + } transactions .iter() .map(|_| Ok(TransactionImportResult::Current)) @@ -128,9 +134,16 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, _chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> + fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails { + + // keep the pending nonces up to date + if let Ok(ref sender) = transaction.sender() { + let nonce = self.last_nonce(sender).unwrap_or(chain.latest_nonce(sender)); + self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); + } + // lets assume that all txs are valid self.imported_transactions.lock().unwrap().push(transaction); @@ -200,7 +213,9 @@ impl MinerService for TestMinerService { } fn nonce(&self, _chain: &BlockChainClient, address: &Address) -> U256 { - self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.nonce(address).clone()) + // we assume all transactions are in a pending block, ignoring the + // reality of gas limits. + self.last_nonce(address).unwrap_or(U256::zero()) } fn code(&self, _chain: &BlockChainClient, address: &Address) -> Option { From 1de7ea090c3aa27fd3084910c3ce9d79fee57172 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:23:24 +0200 Subject: [PATCH 15/88] add informative comment on transaction::Action --- ethcore/src/types/transaction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 842decd88..a6b4c1781 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -36,6 +36,7 @@ pub enum Action { /// Create creates new contract. Create, /// Calls contract at given address. + /// In the case of a transfer, this is the receiver's address.' Call(Address), } From 4c55e4968ef0fba267e9df2cc433a80133b31b83 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:27:03 +0200 Subject: [PATCH 16/88] add eth_blockNumber, eth_TransactionCount integration tests. also adds an EthTester struct for more test flexibility. --- rpc/src/v1/tests/integration/eth.rs | 123 +++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 10 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index a2640203f..3c897dbb3 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -17,17 +17,19 @@ //! rpc integration tests. use std::collections::HashMap; use std::sync::Arc; +use std::str::FromStr; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; use ethcore::ethereum; -use ethminer::ExternalMiner; +use ethcore::transaction::{Transaction, Action}; +use ethminer::{MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; use util::hash::{Address, FixedHash}; -use util::numbers::U256; -use util::keys::{TestAccount, TestAccountProvider}; +use util::numbers::{Uint, U256}; +use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; use ethjson::blockchain::BlockChain; @@ -35,6 +37,13 @@ use v1::traits::eth::Eth; use v1::impls::EthClient; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; +struct EthTester { + _client: Arc, + _miner: Arc, + accounts: Arc, + handler: IoHandler, +} + #[test] fn harness_works() { let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); @@ -44,7 +53,7 @@ fn harness_works() { #[test] fn eth_get_balance() { let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); - chain_harness(chain, |handler| { + chain_harness(chain, |tester| { // final account state let req_latest = r#"{ "jsonrpc": "2.0", @@ -52,8 +61,8 @@ fn eth_get_balance() { "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], "id": 1 }"#; - let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#; - assert_eq!(&handler.handle_request(req_latest).unwrap(), res_latest); + let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest); // non-existant account let req_new_acc = r#"{ @@ -63,8 +72,94 @@ fn eth_get_balance() { "id": 3 }"#; - let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#; - assert_eq!(&handler.handle_request(req_new_acc).unwrap(), res_new_acc); + let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc); + }); +} + +#[test] +fn eth_block_number() { + let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); + chain_harness(chain, |tester| { + let req_number = r#"{ + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": [], + "id": 1 + }"#; + + let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number); + }); +} + +#[cfg(test)] +#[test] +fn eth_transaction_count() { + let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); + chain_harness(chain, |tester| { + let address = tester.accounts.new_account("123").unwrap(); + + let req_before = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 15 + }"#; + + let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; + + + assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); + + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.fake_sign(address.clone()); + + let req_send_trans = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a" + }], + "id": 16 + }"#; + + // dispatch the transaction. + tester.handler.handle_request(&req_send_trans).unwrap(); + + // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. + let req_after_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 17 + }"#; + + let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest); + + // the pending transactions should have been updated. + let req_after_pending = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"], + "id": 18 + }"#; + + let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending); }); } @@ -89,7 +184,7 @@ fn miner_service() -> Arc { // given a blockchain, this harness will create an EthClient wrapping it // which tests can pass specially crafted requests to. fn chain_harness(chain: BlockChain, mut cb: F) -> U - where F: FnMut(&IoHandler) -> U { + where F: FnMut(&EthTester) -> U { let genesis = Genesis::from(chain.genesis()); let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); @@ -120,5 +215,13 @@ fn chain_harness(chain: BlockChain, mut cb: F) -> U let handler = IoHandler::new(); let delegate = eth_client.to_delegate(); handler.add_delegate(delegate); - cb(&handler) + + let tester = EthTester { + _miner: miner_service, + _client: client, + accounts: account_provider, + handler: handler, + }; + + cb(&tester) } From 7ee23240f08a4ecf5d5f053c45498c76eedae787 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 15:14:02 +0200 Subject: [PATCH 17/88] fix travis test build --- Cargo.lock | 2 ++ rpc/Cargo.toml | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dbcd1825..1a5b61a3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,7 +326,9 @@ dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore 1.2.0", + "ethcore-devtools 1.2.0", "ethcore-util 1.2.0", + "ethjson 0.1.0", "ethminer 1.2.0", "ethsync 1.2.0", "json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 23fef5d06..61b51cf88 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,6 +19,8 @@ ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethminer = { path = "../miner" } +ethjson = { path = "../json" } +ethcore-devtools = { path = "../devtools" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } @@ -29,10 +31,6 @@ json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } serde_codegen = { version = "0.7.0", optional = true } syntex = "^0.32.0" -[dev-dependencies] -ethjson = { path = "../json" } -ethcore-devtools = { path = "../devtools" } - [features] default = ["serde_codegen"] nightly = ["serde_macros"] From e7791c220a3ea76e3d8dd6fb017b8bd9ee856dad Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 26 May 2016 13:26:07 +0200 Subject: [PATCH 18/88] rebase fixes and address style concern --- rpc/src/v1/tests/helpers/miner_service.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 36296613c..600f88508 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -121,11 +121,9 @@ impl MinerService for TestMinerService { // lets assume that all txs are valid self.imported_transactions.lock().unwrap().extend_from_slice(&transactions); - for transaction in &transactions { - if let Ok(ref sender) = transaction.sender() { - let nonce = self.last_nonce(sender).unwrap_or(fetch_account(sender).nonce); - self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); - } + for sender in transactions.iter().filter_map(|t| t.sender().ok()) { + let nonce = self.last_nonce(&sender).unwrap_or(fetch_account(&sender).nonce); + self.last_nonces.write().unwrap().insert(sender, nonce + U256::from(1)); } transactions .iter() From 9d4cd7b73e657c99e1704033e69f9ab414d9482e Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 26 May 2016 13:30:19 +0200 Subject: [PATCH 19/88] assert the transaction is being signed correctly --- rpc/src/v1/tests/integration/eth.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index 3c897dbb3..386b72cf7 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -99,6 +99,7 @@ fn eth_transaction_count() { let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); chain_harness(chain, |tester| { let address = tester.accounts.new_account("123").unwrap(); + let secret = tester.accounts.account_secret(&address).unwrap(); let req_before = r#"{ "jsonrpc": "2.0", @@ -119,7 +120,7 @@ fn eth_transaction_count() { action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), value: U256::from(0x9184e72au64), data: vec![] - }.fake_sign(address.clone()); + }.sign(&secret); let req_send_trans = r#"{ "jsonrpc": "2.0", @@ -134,8 +135,10 @@ fn eth_transaction_count() { "id": 16 }"#; + let res_send_trans = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":16}"#; + // dispatch the transaction. - tester.handler.handle_request(&req_send_trans).unwrap(); + assert_eq!(tester.handler.handle_request(&req_send_trans).unwrap(), res_send_trans); // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. let req_after_latest = r#"{ From c021ecd13bd9a0005086be311cd68e7c95ae5528 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 27 May 2016 18:40:48 +0200 Subject: [PATCH 20/88] move "integration" tests out into main module --- rpc/src/v1/tests/{integration => }/eth.rs | 1 - rpc/src/v1/tests/helpers/mod.rs | 2 +- rpc/src/v1/tests/integration/mod.rs | 52 ----------------------- rpc/src/v1/tests/mocked/mod.rs | 3 +- rpc/src/v1/tests/mod.rs | 35 ++++++++++++++- 5 files changed, 37 insertions(+), 56 deletions(-) rename rpc/src/v1/tests/{integration => }/eth.rs (99%) delete mode 100644 rpc/src/v1/tests/integration/mod.rs diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/eth.rs similarity index 99% rename from rpc/src/v1/tests/integration/eth.rs rename to rpc/src/v1/tests/eth.rs index 386b72cf7..eac5bafcb 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -110,7 +110,6 @@ fn eth_transaction_count() { let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; - assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); let t = Transaction { diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index 9b321af98..1b8f9e256 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -20,4 +20,4 @@ mod sync_provider; mod miner_service; pub use self::sync_provider::{Config, TestSyncProvider}; -pub use self::miner_service::{TestMinerService}; +pub use self::miner_service::TestMinerService; diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs deleted file mode 100644 index 4a845c074..000000000 --- a/rpc/src/v1/tests/integration/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 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 . - -//! Integration tests for the JSONRPC APIs - -// extract a chain from the given JSON file, -// stored in ethcore/res/ethereum/tests/. -// -// usage: -// `extract_chain!("Folder/File")` will load Folder/File.json and extract -// the first block chain stored within. -// -// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and -// extract the chain with that name. This will panic if no chain by that name -// is found. -macro_rules! extract_chain { - ($file:expr, $name:expr) => {{ - const RAW_DATA: &'static [u8] = - include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); - let mut chain = None; - for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { - if name == $name { - chain = Some(c); - break; - } - } - chain.unwrap() - }}; - - ($file:expr) => {{ - const RAW_DATA: &'static [u8] = - include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); - - ::ethjson::blockchain::Test::load(RAW_DATA) - .unwrap().into_iter().next().unwrap().1 - }}; -} - -mod eth; \ No newline at end of file diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index 98caf6e08..dc09d998d 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! RPC serialization tests. +//! RPC mocked tests. Most of these test that the RPC server is serializing and forwarding +//! method calls properly. mod eth; mod net; diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 78a6a674f..3455bfd1f 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -2,7 +2,40 @@ pub mod helpers; +// extract a chain from the given JSON file, +// stored in ethcore/res/ethereum/tests/. +// +// usage: +// `extract_chain!("Folder/File")` will load Folder/File.json and extract +// the first block chain stored within. +// +// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and +// extract the chain with that name. This will panic if no chain by that name +// is found. +macro_rules! extract_chain { + ($file:expr, $name:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); + let mut chain = None; + for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { + if name == $name { + chain = Some(c); + break; + } + } + chain.unwrap() + }}; + + ($file:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); + + ::ethjson::blockchain::Test::load(RAW_DATA) + .unwrap().into_iter().next().unwrap().1 + }}; +} + #[cfg(test)] mod mocked; #[cfg(test)] -mod integration; +mod eth; From 6f93ecf1d2d1217cdd3c81e1085e453409faafd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 27 May 2016 15:46:07 +0200 Subject: [PATCH 21/88] Exposing types from RPC --- Cargo.lock | 2 +- parity/signer.rs | 2 +- rpc/Cargo.toml | 1 - rpc/src/lib.rs | 1 - rpc/src/v1/mod.rs | 4 +-- rpc/src/v1/types/block.rs | 23 ++++++++++++ rpc/src/v1/types/block_number.rs | 4 +++ {signer/src => rpc/src/v1}/types/bytes.rs | 0 rpc/src/v1/types/call_request.rs | 8 +++++ rpc/src/v1/types/filter.rs | 11 ++++++ rpc/src/v1/types/index.rs | 1 + rpc/src/v1/types/log.rs | 10 ++++++ rpc/src/v1/types/mod.rs | 2 ++ rpc/src/v1/types/mod.rs.in | 6 ++-- rpc/src/v1/types/optionals.rs | 3 ++ rpc/src/v1/types/receipt.rs | 9 +++++ rpc/src/v1/types/sync.rs | 7 ++++ rpc/src/v1/types/trace.rs | 35 +++++++++++++++++++ rpc/src/v1/types/trace_filter.rs | 5 +++ rpc/src/v1/types/transaction.rs | 12 +++++++ .../src/v1}/types/transaction_request.rs | 4 +-- signer/Cargo.toml | 3 +- signer/src/lib.rs | 2 +- signer/src/signing_queue.rs | 4 +-- signer/src/types/mod.rs.in | 11 ++++-- signer/src/ws_server.rs | 4 +-- 26 files changed, 156 insertions(+), 18 deletions(-) rename {signer/src => rpc/src/v1}/types/bytes.rs (100%) rename {signer/src => rpc/src/v1}/types/transaction_request.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 66df9192a..6298ef7ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,7 +331,6 @@ dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore 1.2.0", - "ethcore-signer 1.2.0", "ethcore-util 1.2.0", "ethminer 1.2.0", "ethsync 1.2.0", @@ -353,6 +352,7 @@ version = "1.2.0" dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-rpc 1.2.0", "ethcore-util 1.2.0", "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)", diff --git a/parity/signer.rs b/parity/signer.rs index e7f7a9cb9..c78ad36ad 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -54,7 +54,7 @@ pub fn start(conf: Configuration, deps: Dependencies) -> Option { } #[cfg(not(feature = "ethcore-signer"))] -pub fn start(conf: Configuration) -> !{ +pub fn start(conf: Configuration) -> Option { if !conf.enabled { return None; } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c8bfa0485..2cdbb0a2b 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,7 +19,6 @@ ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethminer = { path = "../miner" } -ethcore-signer = { path = "../signer" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index ae824adf2..7d9818615 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -27,7 +27,6 @@ extern crate serde_json; extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_util as util; -extern crate ethcore_signer as signer; extern crate ethcore; extern crate ethsync; extern crate ethminer; diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index f3bb450f3..b1ab256c0 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -18,12 +18,12 @@ //! //! Compliant with ethereum rpc. -pub mod traits; mod impls; -mod types; mod helpers; +pub mod traits; pub mod tests; +pub mod types; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc}; pub use self::impls::*; diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index c38949c08..5810c85e5 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -18,9 +18,12 @@ use serde::{Serialize, Serializer}; use util::numbers::*; use v1::types::{Bytes, Transaction, OptionalValue}; +/// Block Transactions #[derive(Debug)] pub enum BlockTransactions { + /// Only hashes Hashes(Vec), + /// Full transactions Full(Vec) } @@ -34,38 +37,58 @@ impl Serialize for BlockTransactions { } } +/// Block representation #[derive(Debug, Serialize)] pub struct Block { + /// Hash of the block pub hash: OptionalValue, + /// Hash of the parent #[serde(rename="parentHash")] pub parent_hash: H256, + /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, + /// Authors address pub author: Address, // TODO: get rid of this one + /// ? pub miner: Address, + /// State root hash #[serde(rename="stateRoot")] pub state_root: H256, + /// Transactions root hash #[serde(rename="transactionsRoot")] pub transactions_root: H256, + /// Transactions receipts root hash #[serde(rename="receiptsRoot")] pub receipts_root: H256, + /// Block number pub number: OptionalValue, + /// Gas Used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Gas Limit #[serde(rename="gasLimit")] pub gas_limit: U256, + /// Extra data #[serde(rename="extraData")] pub extra_data: Bytes, + /// Logs bloom #[serde(rename="logsBloom")] pub logs_bloom: H2048, + /// Timestamp pub timestamp: U256, + /// Difficulty pub difficulty: U256, + /// Total difficulty #[serde(rename="totalDifficulty")] pub total_difficulty: U256, + /// Seal fields #[serde(rename="sealFields")] pub seal_fields: Vec, + /// Uncles' hashes pub uncles: Vec, + /// Transactions pub transactions: BlockTransactions } diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index 071486afd..e2d150c66 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -21,9 +21,13 @@ use ethcore::client::BlockID; /// Represents rpc api block number param. #[derive(Debug, PartialEq, Clone)] pub enum BlockNumber { + /// Number Num(u64), + /// Latest block Latest, + /// Earliest block (genesis) Earliest, + /// Pending block (being mined) Pending } diff --git a/signer/src/types/bytes.rs b/rpc/src/v1/types/bytes.rs similarity index 100% rename from signer/src/types/bytes.rs rename to rpc/src/v1/types/bytes.rs diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs index 045b1cd9b..50ebbd1f0 100644 --- a/rpc/src/v1/types/call_request.rs +++ b/rpc/src/v1/types/call_request.rs @@ -18,15 +18,23 @@ use util::hash::Address; use util::numbers::U256; use v1::types::Bytes; +/// Call request #[derive(Debug, Default, PartialEq, Deserialize)] pub struct CallRequest { + /// From pub from: Option
, + /// To pub to: Option
, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: Option, + /// Gas pub gas: Option, + /// Value pub value: Option, + /// Data pub data: Option, + /// Nonce pub nonce: Option, } diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index e50ec9c32..77a3f0500 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -22,10 +22,14 @@ use v1::types::BlockNumber; use ethcore::filter::Filter as EthFilter; use ethcore::client::BlockID; +/// Variadic value #[derive(Debug, PartialEq, Clone)] pub enum VariadicValue where T: Deserialize { + /// Single Single(T), + /// List Multiple(Vec), + /// None Null, } @@ -44,17 +48,24 @@ impl Deserialize for VariadicValue where T: Deserialize { } } +/// Filter Address pub type FilterAddress = VariadicValue
; +/// Topic pub type Topic = VariadicValue; +/// Filter #[derive(Debug, PartialEq, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Filter { + /// From Block #[serde(rename="fromBlock")] pub from_block: Option, + /// To Block #[serde(rename="toBlock")] pub to_block: Option, + /// Address pub address: Option, + /// Topics pub topics: Option>, } diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index e7cbbd255..d7b17aea2 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -22,6 +22,7 @@ use serde::de::Visitor; pub struct Index(usize); impl Index { + /// Convert to usize pub fn value(&self) -> usize { self.0 } diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 426ca68f1..72a482d1b 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -18,21 +18,31 @@ use util::numbers::*; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use v1::types::Bytes; +/// Log #[derive(Debug, Serialize, PartialEq, Eq, Hash, Clone)] pub struct Log { + /// Address pub address: Address, + /// Topics pub topics: Vec, + /// Data pub data: Bytes, + /// Block Hash #[serde(rename="blockHash")] pub block_hash: Option, + /// Block Number #[serde(rename="blockNumber")] pub block_number: Option, + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: Option, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: Option, + /// Log Index #[serde(rename="logIndex")] pub log_index: Option, + /// Log Type #[serde(rename="type")] pub log_type: String, } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index adf9be071..c1bc34407 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Structures used in RPC communication + #[cfg(feature = "serde_macros")] include!("mod.rs.in"); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 9d7fc882a..824a061ef 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +mod bytes; mod block; mod block_number; mod filter; @@ -22,13 +23,13 @@ mod log; mod optionals; mod sync; mod transaction; +mod transaction_request; mod call_request; mod receipt; mod trace; mod trace_filter; -pub use signer::types::bytes::Bytes; -pub use signer::types::transaction_request::TransactionRequest; +pub use self::bytes::Bytes; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::filter::Filter; @@ -37,6 +38,7 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; +pub use self::transaction_request::TransactionRequest; pub use self::call_request::CallRequest; pub use self::receipt::Receipt; pub use self::trace::Trace; diff --git a/rpc/src/v1/types/optionals.rs b/rpc/src/v1/types/optionals.rs index 5db272251..2ed272ade 100644 --- a/rpc/src/v1/types/optionals.rs +++ b/rpc/src/v1/types/optionals.rs @@ -17,9 +17,12 @@ use serde::{Serialize, Serializer}; use serde_json::Value; +/// Optional value #[derive(Debug)] pub enum OptionalValue where T: Serialize { + /// Some Value(T), + /// None Null } diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index 51d914e1a..32a7f5945 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -19,22 +19,31 @@ use util::hash::{Address, H256}; use v1::types::Log; use ethcore::receipt::LocalizedReceipt; +/// Receipt #[derive(Debug, Serialize)] pub struct Receipt { + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: H256, + /// Transaction index #[serde(rename="transactionIndex")] pub transaction_index: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: H256, + /// Block number #[serde(rename="blockNumber")] pub block_number: U256, + /// Cumulative gas used #[serde(rename="cumulativeGasUsed")] pub cumulative_gas_used: U256, + /// Gas used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Contract address #[serde(rename="contractAddress")] pub contract_address: Option
, + /// Logs pub logs: Vec, } diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index c0e480140..6d750425e 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -17,19 +17,26 @@ use serde::{Serialize, Serializer}; use util::numbers::*; +/// Sync info #[derive(Default, Debug, Serialize, PartialEq)] pub struct SyncInfo { + /// Starting block #[serde(rename="startingBlock")] pub starting_block: U256, + /// Current block #[serde(rename="currentBlock")] pub current_block: U256, + /// Highest block seen so far #[serde(rename="highestBlock")] pub highest_block: U256, } +/// Sync status #[derive(Debug, PartialEq)] pub enum SyncStatus { + /// Info when syncing Info(SyncInfo), + /// Not syncing None } diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index 4cd1ac408..6ea58543a 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -19,11 +19,16 @@ use ethcore::trace::trace; use ethcore::trace::LocalizedTrace; use v1::types::Bytes; +/// Create response #[derive(Debug, Serialize)] pub struct Create { + /// Sender from: Address, + /// Value value: U256, + /// Gas gas: U256, + /// Initialization code init: Bytes, } @@ -38,12 +43,18 @@ impl From for Create { } } +/// Call response #[derive(Debug, Serialize)] pub struct Call { + /// Sender from: Address, + /// Recipient to: Address, + /// Transfered Value value: U256, + /// Gas gas: U256, + /// Input data input: Bytes, } @@ -59,10 +70,13 @@ impl From for Call { } } +/// Action #[derive(Debug, Serialize)] pub enum Action { + /// Call #[serde(rename="call")] Call(Call), + /// Create #[serde(rename="create")] Create(Create), } @@ -76,10 +90,13 @@ impl From for Action { } } +/// Call Result #[derive(Debug, Serialize)] pub struct CallResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Output bytes output: Bytes, } @@ -92,11 +109,15 @@ impl From for CallResult { } } +/// Craete Result #[derive(Debug, Serialize)] pub struct CreateResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Code code: Bytes, + /// Assigned address address: Address, } @@ -110,14 +131,19 @@ impl From for CreateResult { } } +/// Response #[derive(Debug, Serialize)] pub enum Res { + /// Call #[serde(rename="call")] Call(CallResult), + /// Create #[serde(rename="create")] Create(CreateResult), + /// Call failure #[serde(rename="failedCall")] FailedCall, + /// Creation failure #[serde(rename="failedCreate")] FailedCreate, } @@ -133,19 +159,28 @@ impl From for Res { } } +/// Trace #[derive(Debug, Serialize)] pub struct Trace { + /// Action action: Action, + /// Result result: Res, + /// Trace address #[serde(rename="traceAddress")] trace_address: Vec, + /// Subtraces subtraces: U256, + /// Transaction position #[serde(rename="transactionPosition")] transaction_position: U256, + /// Transaction hash #[serde(rename="transactionHash")] transaction_hash: H256, + /// Block Number #[serde(rename="blockNumber")] block_number: U256, + /// Block Hash #[serde(rename="blockHash")] block_hash: H256, } diff --git a/rpc/src/v1/types/trace_filter.rs b/rpc/src/v1/types/trace_filter.rs index 3d45f4c79..ee2f231f0 100644 --- a/rpc/src/v1/types/trace_filter.rs +++ b/rpc/src/v1/types/trace_filter.rs @@ -21,14 +21,19 @@ use ethcore::client::BlockID; use ethcore::client; use super::BlockNumber; +/// Trace filter #[derive(Debug, PartialEq, Deserialize)] pub struct TraceFilter { + /// From block #[serde(rename="fromBlock")] pub from_block: Option, + /// To block #[serde(rename="toBlock")] pub to_block: Option, + /// From address #[serde(rename="fromAddress")] pub from_address: Option>, + /// To address #[serde(rename="toAddress")] pub to_address: Option>, } diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 8a46d5e15..1c9a41084 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -18,22 +18,34 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction}; use v1::types::{Bytes, OptionalValue}; +/// Transaction #[derive(Debug, Default, Serialize)] pub struct Transaction { + /// Hash pub hash: H256, + /// Nonce pub nonce: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: OptionalValue, + /// Block number #[serde(rename="blockNumber")] pub block_number: OptionalValue, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: OptionalValue, + /// Sender pub from: Address, + /// Recipient pub to: OptionalValue
, + /// Transfered value pub value: U256, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: U256, + /// Gas pub gas: U256, + /// Data pub input: Bytes } diff --git a/signer/src/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs similarity index 98% rename from signer/src/types/transaction_request.rs rename to rpc/src/v1/types/transaction_request.rs index 83840515b..1b51e6b12 100644 --- a/signer/src/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -18,7 +18,7 @@ use util::hash::Address; use util::numbers::U256; -use types::bytes::Bytes; +use v1::types::bytes::Bytes; /// Transaction request coming from RPC #[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] @@ -47,7 +47,7 @@ mod tests { use serde_json; use util::numbers::{U256}; use util::hash::Address; - use types::bytes::Bytes; + use v1::types::bytes::Bytes; use super::*; #[test] diff --git a/signer/Cargo.toml b/signer/Cargo.toml index be77a3fd9..59c7f90b2 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -16,10 +16,11 @@ syntex = "^0.32.0" serde = "0.7.0" serde_json = "0.7.0" rustc-serialize = "0.3" -ethcore-util = { path = "../util" } log = "0.3" env_logger = "0.3" ws = "0.4.7" +ethcore-util = { path = "../util" } +ethcore-rpc = { path = "../rpc" } serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.69", optional = true} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index 13f8d2fa6..4317338e0 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -49,11 +49,11 @@ extern crate serde_json; extern crate rustc_serialize; extern crate ethcore_util as util; +extern crate ethcore_rpc as rpc; extern crate ws; mod signing_queue; mod ws_server; -pub mod types; pub use ws_server::*; diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs index 7758f5df3..611d467c2 100644 --- a/signer/src/signing_queue.rs +++ b/signer/src/signing_queue.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use std::collections::HashSet; -use types::transaction_request::TransactionRequest; +use rpc::v1::types::TransactionRequest; pub trait SigningQueue { fn add_request(&mut self, transaction: TransactionRequest); @@ -45,7 +45,7 @@ mod test { use std::collections::HashSet; use util::hash::Address; use util::numbers::U256; - use types::transaction_request::TransactionRequest; + use rpc::v1::types::TransactionRequest; use super::*; #[test] diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in index 986e3d6e2..a59f81ece 100644 --- a/signer/src/types/mod.rs.in +++ b/signer/src/types/mod.rs.in @@ -14,5 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -pub mod transaction_request; -pub mod bytes; + + + + + + + + +// TODO [ToDr] Types are empty for now. But they are about to come. diff --git a/signer/src/ws_server.rs b/signer/src/ws_server.rs index 9be392e69..d2ab02d66 100644 --- a/signer/src/ws_server.rs +++ b/signer/src/ws_server.rs @@ -31,14 +31,14 @@ pub enum ServerError { /// Wrapped `std::io::Error` IoError(std::io::Error), /// Other `ws-rs` error - Other(ws::Error) + WebSocket(ws::Error) } impl From for ServerError { fn from(err: ws::Error) -> Self { match err.kind { ws::ErrorKind::Io(e) => ServerError::IoError(e), - _ => ServerError::Other(err), + _ => ServerError::WebSocket(err), } } } From f85e409ff7f68b3d8061206afc8f7f914c778f7e Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 27 May 2016 16:35:52 +0200 Subject: [PATCH 22/88] Make sure downloaded blocks are unmarked on send error --- sync/src/chain.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index e66fce0d5..6a54c648f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -862,16 +862,12 @@ impl ChainSync { warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); } } - match sync.send(peer_id, packet_id, packet) { - Err(e) => { - debug!(target:"sync", "Error sending request: {:?}", e); - sync.disable_peer(peer_id); - } - Ok(_) => { - let mut peer = self.peers.get_mut(&peer_id).unwrap(); - peer.asking = asking; - peer.ask_time = time::precise_time_s(); - } + let mut peer = self.peers.get_mut(&peer_id).unwrap(); + peer.asking = asking; + peer.ask_time = time::precise_time_s(); + if let Err(e) = sync.send(peer_id, packet_id, packet) { + debug!(target:"sync", "Error sending request: {:?}", e); + sync.disable_peer(peer_id); } } From d1fc5a561180576cc865707982f0b305620f3335 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 27 May 2016 16:49:29 +0200 Subject: [PATCH 23/88] Tweaked some constansts for slower machines --- ethcore/src/client/client.rs | 2 +- sync/src/chain.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 13d678c14..ab1c21af1 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -254,7 +254,7 @@ impl Client where V: Verifier { /// This is triggered by a message coming from a block queue when the block is ready for insertion pub fn import_verified_blocks(&self, io: &IoChannel) -> usize { - let max_blocks_to_import = 128; + let max_blocks_to_import = 64; let mut imported_blocks = Vec::with_capacity(max_blocks_to_import); let mut invalid_blocks = HashSet::new(); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 6a54c648f..dde287a57 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -133,7 +133,7 @@ const NODE_DATA_PACKET: u8 = 0x0e; const GET_RECEIPTS_PACKET: u8 = 0x0f; const RECEIPTS_PACKET: u8 = 0x10; -const CONNECTION_TIMEOUT_SEC: f64 = 10f64; +const CONNECTION_TIMEOUT_SEC: f64 = 15f64; #[derive(Copy, Clone, Eq, PartialEq, Debug)] /// Sync state From 0e905a06d937a745435a6fe0a50d1ba873874c5d Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 27 May 2016 17:26:50 +0200 Subject: [PATCH 24/88] Tweaked propagation order --- sync/src/chain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index dde287a57..63ab8bcc8 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1255,15 +1255,15 @@ impl ChainSync { } fn propagate_latest_blocks(&mut self, io: &mut SyncIo) { - self.propagate_new_transactions(io); let chain_info = io.chain().chain_info(); if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { - let blocks = self.propagate_blocks(&chain_info, io); let hashes = self.propagate_new_hashes(&chain_info, io); + let blocks = self.propagate_blocks(&chain_info, io); if blocks != 0 || hashes != 0 { trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes); } } + self.propagate_new_transactions(io); self.last_sent_block_number = chain_info.best_block_number; } From 1e8bf8c89df7b9db69726441a92d020f49d45cb7 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 27 May 2016 18:57:12 +0200 Subject: [PATCH 25/88] More tweaks --- ethcore/src/tests/client.rs | 4 ++-- sync/src/chain.rs | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index ee2cb9c3c..d734b0b47 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -115,7 +115,7 @@ fn can_collect_garbage() { fn can_handle_long_fork() { let client_result = generate_dummy_client(1200); let client = client_result.reference(); - for _ in 0..10 { + for _ in 0..20 { client.import_verified_blocks(&IoChannel::disconnected()); } assert_eq!(1200, client.chain_info().best_block_number); @@ -124,7 +124,7 @@ fn can_handle_long_fork() { push_blocks_to_client(client, 49, 1201, 800); push_blocks_to_client(client, 53, 1201, 600); - for _ in 0..20 { + for _ in 0..40 { client.import_verified_blocks(&IoChannel::disconnected()); } assert_eq!(2000, client.chain_info().best_block_number); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 63ab8bcc8..63f699c9e 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -113,11 +113,12 @@ const MAX_HEADERS_TO_SEND: usize = 512; const MAX_NODE_DATA_TO_SEND: usize = 1024; const MAX_RECEIPTS_TO_SEND: usize = 1024; const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256; -const MAX_HEADERS_TO_REQUEST: usize = 256; +const MAX_HEADERS_TO_REQUEST: usize = 128; const MAX_BODIES_TO_REQUEST: usize = 64; const MIN_PEERS_PROPAGATION: usize = 4; const MAX_PEERS_PROPAGATION: usize = 128; const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20; +const SUBCHAIN_SIZE: usize = 64; const STATUS_PACKET: u8 = 0x00; const NEW_BLOCK_HASHES_PACKET: u8 = 0x01; @@ -639,7 +640,7 @@ impl ChainSync { self.sync_peer(io, p, false); } } - if !self.peers.values().any(|p| p.asking != PeerAsking::Nothing) { + if self.state != SyncState::Waiting && !self.peers.values().any(|p| p.asking != PeerAsking::Nothing) { self.complete_sync(); } } @@ -665,7 +666,7 @@ impl ChainSync { return; } if self.state == SyncState::Waiting { - trace!(target: "sync", "Waiting for block queue"); + trace!(target: "sync", "Waiting for the block queue"); return; } (peer.latest_hash.clone(), peer.difficulty.clone()) @@ -689,7 +690,7 @@ impl ChainSync { // Request subchain headers trace!(target: "sync", "Starting sync with better chain"); let last = self.last_imported_hash.clone(); - self.request_headers_by_hash(io, peer_id, &last, 128, 255, false, PeerAsking::Heads); + self.request_headers_by_hash(io, peer_id, &last, SUBCHAIN_SIZE, MAX_HEADERS_TO_REQUEST - 1, false, PeerAsking::Heads); }, SyncState::Blocks | SyncState::NewBlocks => { if io.chain().block_status(BlockID::Hash(peer_latest)) == BlockStatus::Unknown { @@ -704,6 +705,8 @@ impl ChainSync { fn start_sync_round(&mut self, io: &mut SyncIo) { self.state = SyncState::ChainHead; trace!(target: "sync", "Starting round (last imported count = {:?}, block = {:?}", self.imported_this_round, self.last_imported_block); + // Check if need to retract to find the common block. The problem is that the peers still return headers by hash even + // from the non-canonical part of the tree. So we also retract if nothing has been imported last round. if self.imported_this_round.is_some() && self.imported_this_round.unwrap() == 0 && self.last_imported_block > 0 { match io.chain().block_hash(BlockID::Number(self.last_imported_block - 1)) { Some(h) => { @@ -781,9 +784,13 @@ impl ChainSync { match io.chain().import_block(block) { Err(Error::Import(ImportError::AlreadyInChain)) => { + self.last_imported_block = number; + self.last_imported_hash = h.clone(); trace!(target: "sync", "Block already in chain {:?}", h); }, Err(Error::Import(ImportError::AlreadyQueued)) => { + self.last_imported_block = number; + self.last_imported_hash = h.clone(); trace!(target: "sync", "Block already queued {:?}", h); }, Ok(_) => { @@ -856,13 +863,10 @@ impl ChainSync { /// Generic request sender fn send_request(&mut self, sync: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) { - { - let peer = self.peers.get_mut(&peer_id).unwrap(); - if peer.asking != PeerAsking::Nothing { - warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); - } + let peer = self.peers.get_mut(&peer_id).unwrap(); + if peer.asking != PeerAsking::Nothing { + warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking); } - let mut peer = self.peers.get_mut(&peer_id).unwrap(); peer.asking = asking; peer.ask_time = time::precise_time_s(); if let Err(e) = sync.send(peer_id, packet_id, packet) { @@ -1095,6 +1099,7 @@ impl ChainSync { let tick = time::precise_time_s(); for (peer_id, peer) in &self.peers { if peer.asking != PeerAsking::Nothing && (tick - peer.ask_time) > CONNECTION_TIMEOUT_SEC { + trace!(target:"sync", "Timeouted {}", peer_id); io.disconnect_peer(*peer_id); } } From 50e5c88b7b2da1f62d6f076b9ce7a8c04e8da984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 28 May 2016 19:10:17 +0200 Subject: [PATCH 26/88] Fixing compilation --- parity/signer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/signer.rs b/parity/signer.rs index c4a540721..5e3339bcc 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -64,7 +64,7 @@ fn do_start(conf: Configuration, deps: Dependencies) -> SignerServer { server.add_delegate(NetClient::new(&deps.sync).to_delegate()); server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); - server.add_delegate(PersonalClient::new(&deps.secret_store).to_delegate()); + server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate()); server.start(addr) }; From 87d0f09a44a449a7ce6e8cf5861e93b6fcf32b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 28 May 2016 19:30:31 +0200 Subject: [PATCH 27/88] Base for Signer Websockets server (#1158) * Basic signing queue * Adding docs * WebSockets server for signer * Removing TODO * Shortening the syntax * Exposing types from RPC * Fixing indentation * Update main.rs --- Cargo.lock | 33 ++++++ dapps/src/lib.rs | 6 +- parity/cli.rs | 7 ++ parity/main.rs | 22 +++- parity/setup_log.rs | 2 + parity/signer.rs | 67 +++++++++++++ rpc/src/v1/mod.rs | 4 +- rpc/src/v1/types/block.rs | 23 +++++ rpc/src/v1/types/block_number.rs | 4 + rpc/src/v1/types/bytes.rs | 8 +- rpc/src/v1/types/call_request.rs | 8 ++ rpc/src/v1/types/filter.rs | 11 ++ rpc/src/v1/types/index.rs | 1 + rpc/src/v1/types/log.rs | 10 ++ rpc/src/v1/types/mod.rs | 2 + rpc/src/v1/types/mod.rs.in | 4 +- rpc/src/v1/types/optionals.rs | 3 + rpc/src/v1/types/receipt.rs | 9 ++ rpc/src/v1/types/sync.rs | 7 ++ rpc/src/v1/types/trace.rs | 35 +++++++ rpc/src/v1/types/trace_filter.rs | 5 + rpc/src/v1/types/transaction.rs | 12 +++ rpc/src/v1/types/transaction_request.rs | 17 +++- signer/Cargo.toml | 14 ++- signer/build.rs | 27 +++++ signer/src/lib.rs | 23 +++++ signer/src/signing_queue.rs | 74 ++++++++++++++ signer/src/types/mod.rs | 23 +++++ signer/src/types/mod.rs.in | 25 +++++ signer/src/ws_server.rs | 128 ++++++++++++++++++++++++ 30 files changed, 598 insertions(+), 16 deletions(-) create mode 100644 parity/signer.rs create mode 100644 signer/src/signing_queue.rs create mode 100644 signer/src/types/mod.rs create mode 100644 signer/src/types/mod.rs.in create mode 100644 signer/src/ws_server.rs diff --git a/Cargo.lock b/Cargo.lock index 4dbcd1825..6298ef7ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,11 @@ name = "bloomchain" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytes" version = "0.3.0" @@ -347,9 +352,16 @@ version = "1.2.0" dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-rpc 1.2.0", "ethcore-util 1.2.0", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ws 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1161,6 +1173,14 @@ dependencies = [ "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha1" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sha3" version = "0.1.0" @@ -1405,6 +1425,19 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ws" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "sha1 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index c6e75072d..27c215108 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -34,9 +34,9 @@ //! let io = IoHandler::new(); //! io.add_method("say_hello", SayHello); //! let _server = Server::start_unsecure_http( -//! &"127.0.0.1:3030".parse().unwrap(), -//! Arc::new(io) -//! ); +//! &"127.0.0.1:3030".parse().unwrap(), +//! Arc::new(io) +//! ); //! } //! ``` //! diff --git a/parity/cli.rs b/parity/cli.rs index 4bb74f188..60b622bf7 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -97,6 +97,11 @@ API and Console Options: --dapps-pass PASSWORD Specify password for Dapps server. Use only in conjunction with --dapps-user. + --signer Enable Trusted Signer WebSocket endpoint used by + System UIs. + --signer-port PORT Specify the port of Trusted Signer server + [default: 8180]. + Sealing/Mining Options: --force-sealing Force the node to author new blocks as if it were always sealing/mining. @@ -234,6 +239,8 @@ pub struct Args { pub flag_dapps_interface: String, pub flag_dapps_user: Option, pub flag_dapps_pass: Option, + pub flag_signer: bool, + pub flag_signer_port: u16, pub flag_force_sealing: bool, pub flag_author: String, pub flag_usd_per_tx: String, diff --git a/parity/main.rs b/parity/main.rs index e87828f64..62474eded 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -50,6 +50,9 @@ extern crate ethcore_rpc; #[cfg(feature = "dapps")] extern crate ethcore_dapps; +#[cfg(feature = "ethcore-signer")] +extern crate ethcore_signer; + #[macro_use] mod die; mod price_info; @@ -63,6 +66,7 @@ mod io_handler; mod cli; mod configuration; mod migration; +mod signer; use std::io::{Write, Read, BufReader, BufRead}; use std::ops::Deref; @@ -89,6 +93,7 @@ use informant::Informant; use die::*; use cli::print_version; use rpc::RpcServer; +use signer::SignerServer; use dapps::WebappServer; use io_handler::ClientIoHandler; use configuration::Configuration; @@ -231,6 +236,14 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) settings: network_settings.clone(), }); + // Set up a signer + let signer_server = signer::start(signer::Configuration { + enabled: conf.args.flag_signer, + port: conf.args.flag_signer_port, + }, signer::Dependencies { + panic_handler: panic_handler.clone(), + }); + // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), @@ -241,7 +254,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) service.io().register_handler(io_handler).expect("Error registering IO handler"); // Handle exit - wait_for_exit(panic_handler, rpc_server, dapps_server); + wait_for_exit(panic_handler, rpc_server, dapps_server, signer_server); } fn flush_stdout() { @@ -453,7 +466,12 @@ fn execute_account_cli(conf: Configuration) { } } -fn wait_for_exit(panic_handler: Arc, _rpc_server: Option, _dapps_server: Option) { +fn wait_for_exit( + panic_handler: Arc, + _rpc_server: Option, + _dapps_server: Option, + _signer_server: Option + ) { let exit = Arc::new(Condvar::new()); // Handle possible exits diff --git a/parity/setup_log.rs b/parity/setup_log.rs index 0fbc76fb3..4ed153fc2 100644 --- a/parity/setup_log.rs +++ b/parity/setup_log.rs @@ -27,6 +27,8 @@ pub fn setup_log(init: &Option) -> Arc { let mut levels = String::new(); let mut builder = LogBuilder::new(); + // Disable ws info logging by default. + builder.filter(Some("ws"), LogLevelFilter::Warn); builder.filter(None, LogLevelFilter::Info); if env::var("RUST_LOG").is_ok() { diff --git a/parity/signer.rs b/parity/signer.rs new file mode 100644 index 000000000..c78ad36ad --- /dev/null +++ b/parity/signer.rs @@ -0,0 +1,67 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use util::panics::{PanicHandler, ForwardPanic}; +use die::*; + +#[cfg(feature = "ethcore-signer")] +use ethcore_signer as signer; +#[cfg(feature = "ethcore-signer")] +pub use ethcore_signer::Server as SignerServer; +#[cfg(not(feature = "ethcore-signer"))] +pub struct SignerServer; + +pub struct Configuration { + pub enabled: bool, + pub port: u16, +} + +pub struct Dependencies { + pub panic_handler: Arc, +} + +#[cfg(feature = "ethcore-signer")] +pub fn start(conf: Configuration, deps: Dependencies) -> Option { + if !conf.enabled { + return None; + } + + let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| die!("Invalid port specified: {}", conf.port)); + let start_result = signer::Server::start(addr); + + match start_result { + Err(signer::ServerError::IoError(err)) => die_with_io_error("Trusted Signer", err), + Err(e) => die!("Trusted Signer: {:?}", e), + Ok(server) => { + deps.panic_handler.forward_from(&server); + Some(server) + }, + } +} + +#[cfg(not(feature = "ethcore-signer"))] +pub fn start(conf: Configuration) -> Option { + if !conf.enabled { + return None; + } + + die!("Your Parity version has been compiled without Trusted Signer support.") +} + + + + diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index f3bb450f3..b1ab256c0 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -18,12 +18,12 @@ //! //! Compliant with ethereum rpc. -pub mod traits; mod impls; -mod types; mod helpers; +pub mod traits; pub mod tests; +pub mod types; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc}; pub use self::impls::*; diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index c38949c08..5810c85e5 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -18,9 +18,12 @@ use serde::{Serialize, Serializer}; use util::numbers::*; use v1::types::{Bytes, Transaction, OptionalValue}; +/// Block Transactions #[derive(Debug)] pub enum BlockTransactions { + /// Only hashes Hashes(Vec), + /// Full transactions Full(Vec) } @@ -34,38 +37,58 @@ impl Serialize for BlockTransactions { } } +/// Block representation #[derive(Debug, Serialize)] pub struct Block { + /// Hash of the block pub hash: OptionalValue, + /// Hash of the parent #[serde(rename="parentHash")] pub parent_hash: H256, + /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, + /// Authors address pub author: Address, // TODO: get rid of this one + /// ? pub miner: Address, + /// State root hash #[serde(rename="stateRoot")] pub state_root: H256, + /// Transactions root hash #[serde(rename="transactionsRoot")] pub transactions_root: H256, + /// Transactions receipts root hash #[serde(rename="receiptsRoot")] pub receipts_root: H256, + /// Block number pub number: OptionalValue, + /// Gas Used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Gas Limit #[serde(rename="gasLimit")] pub gas_limit: U256, + /// Extra data #[serde(rename="extraData")] pub extra_data: Bytes, + /// Logs bloom #[serde(rename="logsBloom")] pub logs_bloom: H2048, + /// Timestamp pub timestamp: U256, + /// Difficulty pub difficulty: U256, + /// Total difficulty #[serde(rename="totalDifficulty")] pub total_difficulty: U256, + /// Seal fields #[serde(rename="sealFields")] pub seal_fields: Vec, + /// Uncles' hashes pub uncles: Vec, + /// Transactions pub transactions: BlockTransactions } diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index 071486afd..e2d150c66 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -21,9 +21,13 @@ use ethcore::client::BlockID; /// Represents rpc api block number param. #[derive(Debug, PartialEq, Clone)] pub enum BlockNumber { + /// Number Num(u64), + /// Latest block Latest, + /// Earliest block (genesis) Earliest, + /// Pending block (being mined) Pending } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 0dc2d3b31..76d84d0dd 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Serializable wrapper around vector of bytes + use rustc_serialize::hex::ToHex; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; use serde::de::Visitor; @@ -28,7 +30,10 @@ impl Bytes { pub fn new(bytes: Vec) -> Bytes { Bytes(bytes) } - pub fn to_vec(self) -> Vec { self.0 } + /// Convert back to vector + pub fn to_vec(self) -> Vec { + self.0 + } } impl Serialize for Bytes { @@ -80,4 +85,3 @@ mod tests { } } - diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs index 045b1cd9b..50ebbd1f0 100644 --- a/rpc/src/v1/types/call_request.rs +++ b/rpc/src/v1/types/call_request.rs @@ -18,15 +18,23 @@ use util::hash::Address; use util::numbers::U256; use v1::types::Bytes; +/// Call request #[derive(Debug, Default, PartialEq, Deserialize)] pub struct CallRequest { + /// From pub from: Option
, + /// To pub to: Option
, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: Option, + /// Gas pub gas: Option, + /// Value pub value: Option, + /// Data pub data: Option, + /// Nonce pub nonce: Option, } diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index e50ec9c32..77a3f0500 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -22,10 +22,14 @@ use v1::types::BlockNumber; use ethcore::filter::Filter as EthFilter; use ethcore::client::BlockID; +/// Variadic value #[derive(Debug, PartialEq, Clone)] pub enum VariadicValue where T: Deserialize { + /// Single Single(T), + /// List Multiple(Vec), + /// None Null, } @@ -44,17 +48,24 @@ impl Deserialize for VariadicValue where T: Deserialize { } } +/// Filter Address pub type FilterAddress = VariadicValue
; +/// Topic pub type Topic = VariadicValue; +/// Filter #[derive(Debug, PartialEq, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Filter { + /// From Block #[serde(rename="fromBlock")] pub from_block: Option, + /// To Block #[serde(rename="toBlock")] pub to_block: Option, + /// Address pub address: Option, + /// Topics pub topics: Option>, } diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs index e7cbbd255..d7b17aea2 100644 --- a/rpc/src/v1/types/index.rs +++ b/rpc/src/v1/types/index.rs @@ -22,6 +22,7 @@ use serde::de::Visitor; pub struct Index(usize); impl Index { + /// Convert to usize pub fn value(&self) -> usize { self.0 } diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 426ca68f1..72a482d1b 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -18,21 +18,31 @@ use util::numbers::*; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use v1::types::Bytes; +/// Log #[derive(Debug, Serialize, PartialEq, Eq, Hash, Clone)] pub struct Log { + /// Address pub address: Address, + /// Topics pub topics: Vec, + /// Data pub data: Bytes, + /// Block Hash #[serde(rename="blockHash")] pub block_hash: Option, + /// Block Number #[serde(rename="blockNumber")] pub block_number: Option, + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: Option, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: Option, + /// Log Index #[serde(rename="logIndex")] pub log_index: Option, + /// Log Type #[serde(rename="type")] pub log_type: String, } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index adf9be071..c1bc34407 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Structures used in RPC communication + #[cfg(feature = "serde_macros")] include!("mod.rs.in"); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index d896a64dc..824a061ef 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +mod bytes; mod block; mod block_number; -mod bytes; mod filter; mod index; mod log; @@ -29,9 +29,9 @@ mod receipt; mod trace; mod trace_filter; +pub use self::bytes::Bytes; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; -pub use self::bytes::Bytes; pub use self::filter::Filter; pub use self::index::Index; pub use self::log::Log; diff --git a/rpc/src/v1/types/optionals.rs b/rpc/src/v1/types/optionals.rs index 5db272251..2ed272ade 100644 --- a/rpc/src/v1/types/optionals.rs +++ b/rpc/src/v1/types/optionals.rs @@ -17,9 +17,12 @@ use serde::{Serialize, Serializer}; use serde_json::Value; +/// Optional value #[derive(Debug)] pub enum OptionalValue where T: Serialize { + /// Some Value(T), + /// None Null } diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index 51d914e1a..32a7f5945 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -19,22 +19,31 @@ use util::hash::{Address, H256}; use v1::types::Log; use ethcore::receipt::LocalizedReceipt; +/// Receipt #[derive(Debug, Serialize)] pub struct Receipt { + /// Transaction Hash #[serde(rename="transactionHash")] pub transaction_hash: H256, + /// Transaction index #[serde(rename="transactionIndex")] pub transaction_index: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: H256, + /// Block number #[serde(rename="blockNumber")] pub block_number: U256, + /// Cumulative gas used #[serde(rename="cumulativeGasUsed")] pub cumulative_gas_used: U256, + /// Gas used #[serde(rename="gasUsed")] pub gas_used: U256, + /// Contract address #[serde(rename="contractAddress")] pub contract_address: Option
, + /// Logs pub logs: Vec, } diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index c0e480140..6d750425e 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -17,19 +17,26 @@ use serde::{Serialize, Serializer}; use util::numbers::*; +/// Sync info #[derive(Default, Debug, Serialize, PartialEq)] pub struct SyncInfo { + /// Starting block #[serde(rename="startingBlock")] pub starting_block: U256, + /// Current block #[serde(rename="currentBlock")] pub current_block: U256, + /// Highest block seen so far #[serde(rename="highestBlock")] pub highest_block: U256, } +/// Sync status #[derive(Debug, PartialEq)] pub enum SyncStatus { + /// Info when syncing Info(SyncInfo), + /// Not syncing None } diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index 4cd1ac408..6ea58543a 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -19,11 +19,16 @@ use ethcore::trace::trace; use ethcore::trace::LocalizedTrace; use v1::types::Bytes; +/// Create response #[derive(Debug, Serialize)] pub struct Create { + /// Sender from: Address, + /// Value value: U256, + /// Gas gas: U256, + /// Initialization code init: Bytes, } @@ -38,12 +43,18 @@ impl From for Create { } } +/// Call response #[derive(Debug, Serialize)] pub struct Call { + /// Sender from: Address, + /// Recipient to: Address, + /// Transfered Value value: U256, + /// Gas gas: U256, + /// Input data input: Bytes, } @@ -59,10 +70,13 @@ impl From for Call { } } +/// Action #[derive(Debug, Serialize)] pub enum Action { + /// Call #[serde(rename="call")] Call(Call), + /// Create #[serde(rename="create")] Create(Create), } @@ -76,10 +90,13 @@ impl From for Action { } } +/// Call Result #[derive(Debug, Serialize)] pub struct CallResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Output bytes output: Bytes, } @@ -92,11 +109,15 @@ impl From for CallResult { } } +/// Craete Result #[derive(Debug, Serialize)] pub struct CreateResult { + /// Gas used #[serde(rename="gasUsed")] gas_used: U256, + /// Code code: Bytes, + /// Assigned address address: Address, } @@ -110,14 +131,19 @@ impl From for CreateResult { } } +/// Response #[derive(Debug, Serialize)] pub enum Res { + /// Call #[serde(rename="call")] Call(CallResult), + /// Create #[serde(rename="create")] Create(CreateResult), + /// Call failure #[serde(rename="failedCall")] FailedCall, + /// Creation failure #[serde(rename="failedCreate")] FailedCreate, } @@ -133,19 +159,28 @@ impl From for Res { } } +/// Trace #[derive(Debug, Serialize)] pub struct Trace { + /// Action action: Action, + /// Result result: Res, + /// Trace address #[serde(rename="traceAddress")] trace_address: Vec, + /// Subtraces subtraces: U256, + /// Transaction position #[serde(rename="transactionPosition")] transaction_position: U256, + /// Transaction hash #[serde(rename="transactionHash")] transaction_hash: H256, + /// Block Number #[serde(rename="blockNumber")] block_number: U256, + /// Block Hash #[serde(rename="blockHash")] block_hash: H256, } diff --git a/rpc/src/v1/types/trace_filter.rs b/rpc/src/v1/types/trace_filter.rs index 3d45f4c79..ee2f231f0 100644 --- a/rpc/src/v1/types/trace_filter.rs +++ b/rpc/src/v1/types/trace_filter.rs @@ -21,14 +21,19 @@ use ethcore::client::BlockID; use ethcore::client; use super::BlockNumber; +/// Trace filter #[derive(Debug, PartialEq, Deserialize)] pub struct TraceFilter { + /// From block #[serde(rename="fromBlock")] pub from_block: Option, + /// To block #[serde(rename="toBlock")] pub to_block: Option, + /// From address #[serde(rename="fromAddress")] pub from_address: Option>, + /// To address #[serde(rename="toAddress")] pub to_address: Option>, } diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 8a46d5e15..1c9a41084 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -18,22 +18,34 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction}; use v1::types::{Bytes, OptionalValue}; +/// Transaction #[derive(Debug, Default, Serialize)] pub struct Transaction { + /// Hash pub hash: H256, + /// Nonce pub nonce: U256, + /// Block hash #[serde(rename="blockHash")] pub block_hash: OptionalValue, + /// Block number #[serde(rename="blockNumber")] pub block_number: OptionalValue, + /// Transaction Index #[serde(rename="transactionIndex")] pub transaction_index: OptionalValue, + /// Sender pub from: Address, + /// Recipient pub to: OptionalValue
, + /// Transfered value pub value: U256, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: U256, + /// Gas pub gas: U256, + /// Data pub input: Bytes } diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index f00fa9ef0..1b51e6b12 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -14,19 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! `TransactionRequest` type + use util::hash::Address; use util::numbers::U256; -use v1::types::Bytes; +use v1::types::bytes::Bytes; -#[derive(Debug, Default, PartialEq, Deserialize)] +/// Transaction request coming from RPC +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] pub struct TransactionRequest { + /// Sender pub from: Address, + /// Recipient pub to: Option
, + /// Gas Price #[serde(rename="gasPrice")] pub gas_price: Option, + /// Gas pub gas: Option, + /// Value of transaction in wei pub value: Option, + /// Additional data sent with transaction pub data: Option, + /// Transaction's nonce pub nonce: Option, } @@ -37,7 +47,7 @@ mod tests { use serde_json; use util::numbers::{U256}; use util::hash::Address; - use v1::types::Bytes; + use v1::types::bytes::Bytes; use super::*; #[test] @@ -126,3 +136,4 @@ mod tests { }); } } + diff --git a/signer/Cargo.toml b/signer/Cargo.toml index f72865f4f..59c7f90b2 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -9,13 +9,23 @@ build = "build.rs" [build-dependencies] rustc_version = "0.1" +serde_codegen = { version = "0.7.0", optional = true } +syntex = "^0.32.0" [dependencies] -ethcore-util = { path = "../util" } +serde = "0.7.0" +serde_json = "0.7.0" +rustc-serialize = "0.3" log = "0.3" env_logger = "0.3" +ws = "0.4.7" +ethcore-util = { path = "../util" } +ethcore-rpc = { path = "../rpc" } + +serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.69", optional = true} [features] -default = [] +default = ["serde_codegen"] +nightly = ["serde_macros"] dev = ["clippy"] diff --git a/signer/build.rs b/signer/build.rs index 41b9a1b3e..2bcfc7da5 100644 --- a/signer/build.rs +++ b/signer/build.rs @@ -19,7 +19,34 @@ extern crate rustc_version; use rustc_version::{version_meta, Channel}; fn main() { + serde::main(); if let Channel::Nightly = version_meta().channel { println!("cargo:rustc-cfg=nightly"); } } + +#[cfg(not(feature = "serde_macros"))] +mod serde { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("mod.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod serde { + pub fn main() {} +} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index fd17758d2..4317338e0 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -17,6 +17,8 @@ #![warn(missing_docs)] #![cfg_attr(all(nightly, feature="dev"), feature(plugin))] #![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +// Generated by serde +#![cfg_attr(all(nightly, feature="dev"), allow(redundant_closure_call))] //! Signer module //! @@ -28,12 +30,33 @@ //! and their responsibility is to confirm (or confirm and sign) //! the transaction for you. //! +//! ``` +//! extern crate ethcore_signer; //! +//! use ethcore_signer::Server; +//! +//! fn main() { +//! let _server = Server::start("127.0.0.1:8084".parse().unwrap()); +//! } +//! ``` #[macro_use] extern crate log; extern crate env_logger; +extern crate serde; +extern crate serde_json; +extern crate rustc_serialize; + +extern crate ethcore_util as util; +extern crate ethcore_rpc as rpc; +extern crate ws; + +mod signing_queue; +mod ws_server; + +pub use ws_server::*; + #[cfg(test)] mod tests { #[test] diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs new file mode 100644 index 000000000..611d467c2 --- /dev/null +++ b/signer/src/signing_queue.rs @@ -0,0 +1,74 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashSet; +use rpc::v1::types::TransactionRequest; + +pub trait SigningQueue { + fn add_request(&mut self, transaction: TransactionRequest); + + fn remove_request(&mut self, id: TransactionRequest); + + fn requests(&self) -> &HashSet; +} + +impl SigningQueue for HashSet { + fn add_request(&mut self, transaction: TransactionRequest) { + self.insert(transaction); + } + + fn remove_request(&mut self, id: TransactionRequest) { + self.remove(&id); + } + + fn requests(&self) -> &HashSet { + self + } +} + + +#[cfg(test)] +mod test { + use std::collections::HashSet; + use util::hash::Address; + use util::numbers::U256; + use rpc::v1::types::TransactionRequest; + use super::*; + + #[test] + fn should_work_for_hashset() { + // given + let mut queue = HashSet::new(); + + let request = TransactionRequest { + from: Address::from(1), + to: Some(Address::from(2)), + gas_price: None, + gas: None, + value: Some(U256::from(10_000_000)), + data: None, + nonce: None, + }; + + // when + queue.add_request(request.clone()); + let all = queue.requests(); + + // then + assert_eq!(all.len(), 1); + assert!(all.contains(&request)); + } +} diff --git a/signer/src/types/mod.rs b/signer/src/types/mod.rs new file mode 100644 index 000000000..d5e15046a --- /dev/null +++ b/signer/src/types/mod.rs @@ -0,0 +1,23 @@ +// 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 . + +//! Reusable types with JSON Serialization. + +#[cfg(feature = "serde_macros")] +include!("mod.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in new file mode 100644 index 000000000..a59f81ece --- /dev/null +++ b/signer/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 . + + + + + + + + + +// TODO [ToDr] Types are empty for now. But they are about to come. diff --git a/signer/src/ws_server.rs b/signer/src/ws_server.rs new file mode 100644 index 000000000..d2ab02d66 --- /dev/null +++ b/signer/src/ws_server.rs @@ -0,0 +1,128 @@ +// 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 . + +//! `WebSockets` server. + +use ws; +use std; +use std::thread; +use std::ops::Drop; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::net::SocketAddr; +use util::panics::{PanicHandler, OnPanicListener, MayPanic}; + +/// Signer startup error +#[derive(Debug)] +pub enum ServerError { + /// Wrapped `std::io::Error` + IoError(std::io::Error), + /// Other `ws-rs` error + WebSocket(ws::Error) +} + +impl From for ServerError { + fn from(err: ws::Error) -> Self { + match err.kind { + ws::ErrorKind::Io(e) => ServerError::IoError(e), + _ => ServerError::WebSocket(err), + } + } +} + +/// `WebSockets` server implementation. +pub struct Server { + handle: Option>>, + broadcaster: ws::Sender, + panic_handler: Arc, +} + +impl Server { + /// Starts a new `WebSocket` server in separate thread. + /// Returns a `Server` handle which closes the server when droped. + pub fn start(addr: SocketAddr) -> Result { + let config = { + let mut config = ws::Settings::default(); + config.max_connections = 5; + config.method_strict = true; + config + }; + + // Create WebSocket + let session_id = Arc::new(AtomicUsize::new(1)); + let ws = try!(ws::Builder::new().with_settings(config).build(Factory { + session_id: session_id, + })); + + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); + let broadcaster = ws.broadcaster(); + // Spawn a thread with event loop + let handle = thread::spawn(move || { + ph.catch_panic(move || { + ws.listen(addr).unwrap() + }).unwrap() + }); + + // Return a handle + Ok(Server { + handle: Some(handle), + broadcaster: broadcaster, + panic_handler: panic_handler, + }) + } +} + +impl MayPanic for Server { + fn on_panic(&self, closure: F) where F: OnPanicListener { + self.panic_handler.on_panic(closure); + } +} + +impl Drop for Server { + fn drop(&mut self) { + self.broadcaster.shutdown().expect("WsServer should close nicely."); + self.handle.take().unwrap().join().unwrap(); + } +} + +struct Session { + id: usize, + out: ws::Sender, +} + +impl ws::Handler for Session { + fn on_open(&mut self, _shake: ws::Handshake) -> ws::Result<()> { + try!(self.out.send(format!("Hello client no: {}. We are not implemented yet.", self.id))); + try!(self.out.close(ws::CloseCode::Normal)); + Ok(()) + } +} + +struct Factory { + session_id: Arc, +} + +impl ws::Factory for Factory { + type Handler = Session; + + fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler { + Session { + id: self.session_id.fetch_add(1, Ordering::SeqCst), + out: sender, + } + } +} From ea08dd76a520bc385e451be06e5f55d7efd644c8 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 28 May 2016 21:48:42 +0200 Subject: [PATCH 28/88] remove all possible unsafe code in crypto (#1168) * use #[repr(C)] for all hash types * use a zeroed buffer in crypto::ec::sign * eliminate most usages of unsafe in crypto::ecdh::agree * eliminate all possible unsafety in crypto module --- util/src/crypto.rs | 54 +++++++++++++++++++++++++++------------------- util/src/hash.rs | 1 + 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 3eff70717..b92bb2bae 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -38,13 +38,10 @@ lazy_static! { impl Signature { /// Create a new signature from the R, S and V componenets. pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature { - use std::ptr; let mut ret: Signature = Signature::new(); - unsafe { - let retslice: &mut [u8] = &mut ret; - ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32); - ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32); - } + (&mut ret[0..32]).copy_from_slice(r); + (&mut ret[32..64]).copy_from_slice(s); + ret[64] = v; ret } @@ -145,7 +142,10 @@ impl KeyPair { let (sec, publ) = try!(context.generate_keypair(&mut rng)); let serialized = publ.serialize_vec(context, false); let p: Public = Public::from_slice(&serialized[1..65]); - let s: Secret = unsafe { ::std::mem::transmute(sec) }; + + let mut s = Secret::new(); + s.copy_from_slice(&sec[0..32]); + Ok(KeyPair { secret: s, public: p, @@ -193,12 +193,14 @@ pub mod ec { /// Returns siganture of message hash. pub fn sign(secret: &Secret, message: &H256) -> Result { // TODO: allow creation of only low-s signatures. - use secp256k1::*; + use secp256k1::{Message, key}; + let context = &crypto::SECP256K1; + // no way to create from raw byte array. let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec)); let (rec_id, data) = s.serialize_compact(context); - let mut signature: crypto::Signature = unsafe { ::std::mem::uninitialized() }; + let mut signature = crypto::Signature::new(); signature.clone_from_slice(&data); signature[64] = rec_id.to_i32() as u8; @@ -217,10 +219,12 @@ pub mod ec { let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let sig = rsig.to_standard(context); - let mut pdata: [u8; 65] = [4u8; 65]; - let ptr = pdata[1..].as_mut_ptr(); - let src = public.as_ptr(); - unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; + let pdata: [u8; 65] = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(public); + temp + }; + let publ = try!(key::PublicKey::from_slice(context, &pdata)); match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) { Ok(_) => Ok(true), @@ -252,21 +256,27 @@ pub mod ec { /// ECDH functions #[cfg_attr(feature="dev", allow(similar_names))] pub mod ecdh { - use crypto::*; - use crypto::{self}; + use hash::FixedHash; + use crypto::{self, Secret, Public, CryptoError}; /// Agree on a shared secret - pub fn agree(secret: &Secret, public: &Public, ) -> Result { - use secp256k1::*; + pub fn agree(secret: &Secret, public: &Public) -> Result { + use secp256k1::{ecdh, key}; + let context = &crypto::SECP256K1; - let mut pdata: [u8; 65] = [4u8; 65]; - let ptr = pdata[1..].as_mut_ptr(); - let src = public.as_ptr(); - unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; + let pdata = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(&public[0..64]); + temp + }; + let publ = try!(key::PublicKey::from_slice(context, &pdata)); + // no way to create SecretKey from raw byte array. let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); - let s: Secret = unsafe { ::std::mem::transmute(shared) }; + + let mut s = crypto::Secret::new(); + s.copy_from_slice(&shared[0..32]); Ok(s) } } diff --git a/util/src/hash.rs b/util/src/hash.rs index e1b82b14c..ba96f812c 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -75,6 +75,7 @@ pub fn clean_0x(s: &str) -> &str { macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] + #[repr(C)] /// Unformatted binary data of fixed length. pub struct $from (pub [u8; $size]); From 7f3ba85a3f83a53f949d96ac0f9dedafafa39d9d Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 29 May 2016 00:38:10 +0200 Subject: [PATCH 29/88] Fixed block/hashes propagation --- sync/src/chain.rs | 35 +++++++++++++++++------------------ sync/src/tests/chain.rs | 5 +++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 63f699c9e..2f31f1d47 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1165,24 +1165,23 @@ impl ChainSync { .collect::>() } + + fn select_lagging_peers(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> Vec<(PeerId, BlockNumber)> { + use rand::Rng; + let mut lagging_peers = self.get_lagging_peers(chain_info, io); + // take sqrt(x) peers + let mut count = (self.peers.len() as f64).powf(0.5).round() as usize; + count = min(count, MAX_PEERS_PROPAGATION); + count = max(count, MIN_PEERS_PROPAGATION); + ::rand::thread_rng().shuffle(&mut lagging_peers); + lagging_peers.into_iter().take(count).collect::>() + } + /// propagates latest block to lagging peers fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { - let updated_peers = { - let lagging_peers = self.get_lagging_peers(chain_info, io); - - // sqrt(x)/x scaled to max u32 - let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32; - let lucky_peers = match lagging_peers.len() { - 0 ... MIN_PEERS_PROPAGATION => lagging_peers, - _ => lagging_peers.into_iter().filter(|_| ::rand::random::() < fraction).collect::>() - }; - - // taking at max of MAX_PEERS_PROPAGATION - lucky_peers.iter().map(|&(id, _)| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::>() - }; - + let lucky_peers = self.select_lagging_peers(chain_info, io); let mut sent = 0; - for peer_id in updated_peers { + for (peer_id, _) in lucky_peers { let rlp = ChainSync::create_latest_block_rlp(io.chain()); self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp); self.peers.get_mut(&peer_id).unwrap().latest_hash = chain_info.best_block_hash.clone(); @@ -1194,12 +1193,12 @@ impl ChainSync { /// propagates new known hashes to all peers fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize { - let updated_peers = self.get_lagging_peers(chain_info, io); + let lucky_peers = self.select_lagging_peers(chain_info, io); let mut sent = 0; let last_parent = HeaderView::new(&io.chain().block_header(BlockID::Hash(chain_info.best_block_hash.clone())).unwrap()).parent_hash(); - for (peer_id, peer_number) in updated_peers { + for (peer_id, peer_number) in lucky_peers { let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone(); - if chain_info.best_block_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber { + if chain_info.best_block_number - peer_number > MAX_PEER_LAG_PROPAGATION as BlockNumber { // If we think peer is too far behind just send one latest hash peer_best = last_parent.clone(); } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 2e3ec1f4c..09e83e358 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -159,7 +159,7 @@ fn propagate_hashes() { #[test] fn propagate_blocks() { - let mut net = TestNet::new(2); + let mut net = TestNet::new(20); net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle); net.sync(); @@ -169,7 +169,8 @@ fn propagate_blocks() { assert!(!net.peer(0).queue.is_empty()); // NEW_BLOCK_PACKET - assert_eq!(0x07, net.peer(0).queue[0].packet_id); + let blocks = net.peer(0).queue.iter().filter(|p| p.packet_id == 0x7).count(); + assert!(blocks > 0); } #[test] From a8cf0ddf50835d28198e38e70b8ae67ed0e4c1d4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 29 May 2016 13:09:51 +0200 Subject: [PATCH 30/88] json ipc server version bump --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5dff43d04..79e174cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-ipc-server" version = "0.1.0" -source = "git+https://github.com/ethcore/json-ipc-server.git#fdcba83d00b127c7419fe21406a5b81998f686eb" +source = "git+https://github.com/ethcore/json-ipc-server.git#4a5e18c321a93eddd67efc4865013efaac9c8d19" dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", From 7dfd7e883f5ee15d18260ac77cecf8911b7edb82 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 29 May 2016 13:22:45 +0200 Subject: [PATCH 31/88] another bump --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 79e174cd3..ba5edef97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-ipc-server" version = "0.1.0" -source = "git+https://github.com/ethcore/json-ipc-server.git#4a5e18c321a93eddd67efc4865013efaac9c8d19" +source = "git+https://github.com/ethcore/json-ipc-server.git#4f9226c4f84dcce2385a188374e3b5fc66b63e68" dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", From 1176f6acec6a99e008521f541b857adfe8676e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 29 May 2016 13:25:31 +0200 Subject: [PATCH 32/88] fixing test --- signer/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/signer/src/lib.rs b/signer/src/lib.rs index a39fe68f0..f3a963ac7 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -33,10 +33,11 @@ //! ``` //! extern crate ethcore_signer; //! -//! use ethcore_signer::Server; +//! use ethcore_signer::ServerBuilder; //! //! fn main() { -//! let _server = Server::start("127.0.0.1:8084".parse().unwrap()); +//! let builder = ServerBuilder::new(); +//! let _server = builder.start("127.0.0.1:8084".parse().unwrap()).unwrap(); //! } //! ``` From fb2ea765d5bcf4bec02f5e65fd0f48dd19f36b13 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 27 May 2016 20:04:41 +0200 Subject: [PATCH 33/88] remove default implementations using rpc_unimplemented!() --- rpc/src/v1/traits/eth.rs | 86 +++++++++++++++++------------------ rpc/src/v1/traits/ethcore.rs | 34 +++++++------- rpc/src/v1/traits/net.rs | 6 +-- rpc/src/v1/traits/personal.rs | 8 ++-- rpc/src/v1/traits/rpc.rs | 4 +- rpc/src/v1/traits/traces.rs | 8 ++-- rpc/src/v1/traits/web3.rs | 4 +- 7 files changed, 75 insertions(+), 75 deletions(-) diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index a28f72c5c..1577053f4 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -21,115 +21,115 @@ use jsonrpc_core::*; /// Eth rpc interface. pub trait Eth: Sized + Send + Sync + 'static { /// Returns protocol version. - fn protocol_version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn protocol_version(&self, _: Params) -> Result; /// Returns an object with data about the sync status or false. (wtf?) - fn syncing(&self, _: Params) -> Result { rpc_unimplemented!() } + fn syncing(&self, _: Params) -> Result; /// Returns the number of hashes per second that the node is mining with. - fn hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } + fn hashrate(&self, _: Params) -> Result; /// Returns block author. - fn author(&self, _: Params) -> Result { rpc_unimplemented!() } + fn author(&self, _: Params) -> Result; /// Returns true if client is actively mining new blocks. - fn is_mining(&self, _: Params) -> Result { rpc_unimplemented!() } + fn is_mining(&self, _: Params) -> Result; /// Returns current gas_price. - fn gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn gas_price(&self, _: Params) -> Result; /// Returns accounts list. - fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + fn accounts(&self, _: Params) -> Result; /// Returns highest block number. - fn block_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_number(&self, _: Params) -> Result; /// Returns balance of the given account. - fn balance(&self, _: Params) -> Result { rpc_unimplemented!() } + fn balance(&self, _: Params) -> Result; /// Returns content of the storage at given address. - fn storage_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn storage_at(&self, _: Params) -> Result; /// Returns block with given hash. - fn block_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_by_hash(&self, _: Params) -> Result; /// Returns block with given number. - fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_by_number(&self, _: Params) -> Result; /// Returns the number of transactions sent from given address at given time (block number). - fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_count(&self, _: Params) -> Result; /// Returns the number of transactions in a block with given hash. - fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_transaction_count_by_hash(&self, _: Params) -> Result; /// Returns the number of transactions in a block with given block number. - fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_transaction_count_by_number(&self, _: Params) -> Result; /// Returns the number of uncles in a block with given hash. - fn block_uncles_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_uncles_count_by_hash(&self, _: Params) -> Result; /// Returns the number of uncles in a block with given block number. - fn block_uncles_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_uncles_count_by_number(&self, _: Params) -> Result; /// Returns the code at given address at given time (block number). - fn code_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn code_at(&self, _: Params) -> Result; /// Signs the data with given address signature. - fn sign(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sign(&self, _: Params) -> Result; /// Sends transaction. - fn send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn send_transaction(&self, _: Params) -> Result; /// Sends signed transaction. - fn send_raw_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn send_raw_transaction(&self, _: Params) -> Result; /// Call contract. - fn call(&self, _: Params) -> Result { rpc_unimplemented!() } + fn call(&self, _: Params) -> Result; /// Estimate gas needed for execution of given contract. - fn estimate_gas(&self, _: Params) -> Result { rpc_unimplemented!() } + fn estimate_gas(&self, _: Params) -> Result; /// Get transaction by it's hash. - fn transaction_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_hash(&self, _: Params) -> Result; /// Returns transaction at given block hash and index. - fn transaction_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_block_hash_and_index(&self, _: Params) -> Result; /// Returns transaction by given block number and index. - fn transaction_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_block_number_and_index(&self, _: Params) -> Result; /// Returns transaction receipt. - fn transaction_receipt(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_receipt(&self, _: Params) -> Result; /// Returns an uncles at given block and index. - fn uncle_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_hash_and_index(&self, _: Params) -> Result; /// Returns an uncles at given block and index. - fn uncle_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_number_and_index(&self, _: Params) -> Result; /// Returns available compilers. - fn compilers(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compilers(&self, _: Params) -> Result; /// Compiles lll code. - fn compile_lll(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_lll(&self, _: Params) -> Result; /// Compiles solidity. - fn compile_solidity(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_solidity(&self, _: Params) -> Result; /// Compiles serpent. - fn compile_serpent(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_serpent(&self, _: Params) -> Result; /// Returns logs matching given filter object. - fn logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn logs(&self, _: Params) -> Result; /// Returns the hash of the current block, the seedHash, and the boundary condition to be met. - fn work(&self, _: Params) -> Result { rpc_unimplemented!() } + fn work(&self, _: Params) -> Result; /// Used for submitting a proof-of-work solution. - fn submit_work(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_work(&self, _: Params) -> Result; /// Used for submitting mining hashrate. - fn submit_hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_hashrate(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { @@ -179,22 +179,22 @@ pub trait Eth: Sized + Send + Sync + 'static { // TODO: do filters api properly pub trait EthFilter: Sized + Send + Sync + 'static { /// Returns id of new filter. - fn new_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_filter(&self, _: Params) -> Result; /// Returns id of new block filter. - fn new_block_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_block_filter(&self, _: Params) -> Result; /// Returns id of new block filter. - fn new_pending_transaction_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_pending_transaction_filter(&self, _: Params) -> Result; /// Returns filter changes since last poll. - fn filter_changes(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter_changes(&self, _: Params) -> Result; /// Returns all logs matching given filter (in a range 'from' - 'to'). - fn filter_logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter_logs(&self, _: Params) -> Result; /// Uninstalls filter. - fn uninstall_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uninstall_filter(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 2a2159bd9..3646f6c5a 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -22,55 +22,55 @@ use jsonrpc_core::*; pub trait Ethcore: Sized + Send + Sync + 'static { /// Sets new minimal gas price for mined blocks. - fn set_min_gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_min_gas_price(&self, _: Params) -> Result; /// Sets new gas floor target for mined blocks. - fn set_gas_floor_target(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_gas_floor_target(&self, _: Params) -> Result; /// Sets new extra data for mined blocks. - fn set_extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_extra_data(&self, _: Params) -> Result; /// Sets new author for mined block. - fn set_author(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_author(&self, _: Params) -> Result; /// Sets the limits for transaction queue. - fn set_transactions_limit(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_transactions_limit(&self, _: Params) -> Result; /// Returns current transactions limit. - fn transactions_limit(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transactions_limit(&self, _: Params) -> Result; /// Returns mining extra data. - fn extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn extra_data(&self, _: Params) -> Result; /// Returns mining gas floor target. - fn gas_floor_target(&self, _: Params) -> Result { rpc_unimplemented!() } + fn gas_floor_target(&self, _: Params) -> Result; /// Returns minimal gas price for transaction to be included in queue. - fn min_gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn min_gas_price(&self, _: Params) -> Result; /// Returns latest logs - fn dev_logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn dev_logs(&self, _: Params) -> Result; /// Returns logs levels - fn dev_logs_levels(&self, _: Params) -> Result { rpc_unimplemented!() } + fn dev_logs_levels(&self, _: Params) -> Result; /// Returns chain name - fn net_chain(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_chain(&self, _: Params) -> Result; /// Returns max peers - fn net_max_peers(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_max_peers(&self, _: Params) -> Result; /// Returns network port - fn net_port(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_port(&self, _: Params) -> Result; /// Returns rpc settings - fn rpc_settings(&self, _: Params) -> Result { rpc_unimplemented!() } + fn rpc_settings(&self, _: Params) -> Result; /// Returns node name - fn node_name(&self, _: Params) -> Result { rpc_unimplemented!() } + fn node_name(&self, _: Params) -> Result; /// Returns default extra data - fn default_extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn default_extra_data(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. diff --git a/rpc/src/v1/traits/net.rs b/rpc/src/v1/traits/net.rs index 732d6efb2..56fba3e32 100644 --- a/rpc/src/v1/traits/net.rs +++ b/rpc/src/v1/traits/net.rs @@ -21,14 +21,14 @@ use jsonrpc_core::*; /// Net rpc interface. pub trait Net: Sized + Send + Sync + 'static { /// Returns protocol version. - fn version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn version(&self, _: Params) -> Result; /// Returns number of peers connected to node. - fn peer_count(&self, _: Params) -> Result { rpc_unimplemented!() } + fn peer_count(&self, _: Params) -> Result; /// Returns true if client is actively listening for network connections. /// Otherwise false. - fn is_listening(&self, _: Params) -> Result { rpc_unimplemented!() } + fn is_listening(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs index 0619d7ada..d66161c54 100644 --- a/rpc/src/v1/traits/personal.rs +++ b/rpc/src/v1/traits/personal.rs @@ -22,16 +22,16 @@ use jsonrpc_core::*; pub trait Personal: Sized + Send + Sync + 'static { /// Lists all stored accounts - fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + fn accounts(&self, _: Params) -> Result; /// Creates new account (it becomes new current unlocked account) - fn new_account(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_account(&self, _: Params) -> Result; /// Unlocks specified account for use (can only be one unlocked account at one moment) - fn unlock_account(&self, _: Params) -> Result { rpc_unimplemented!() } + fn unlock_account(&self, _: Params) -> Result; /// Sends transaction and signs it in single call. The account is not unlocked in such case. - fn sign_and_send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sign_and_send_transaction(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/rpc.rs b/rpc/src/v1/traits/rpc.rs index 5c981c8a1..669d0d8c6 100644 --- a/rpc/src/v1/traits/rpc.rs +++ b/rpc/src/v1/traits/rpc.rs @@ -23,10 +23,10 @@ use jsonrpc_core::*; pub trait Rpc: Sized + Send + Sync + 'static { /// Returns supported modules for Geth 1.3.6 - fn modules(&self, _: Params) -> Result { rpc_unimplemented!() } + fn modules(&self, _: Params) -> Result; /// Returns supported modules for Geth 1.4.0 - fn rpc_modules(&self, _: Params) -> Result { rpc_unimplemented!() } + fn rpc_modules(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index b42feede5..54d04b954 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -21,16 +21,16 @@ use jsonrpc_core::*; /// Traces specific rpc interface. pub trait Traces: Sized + Send + Sync + 'static { /// Returns traces matching given filter. - fn filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter(&self, _: Params) -> Result; /// Returns transaction trace at given index. - fn trace(&self, _: Params) -> Result { rpc_unimplemented!() } + fn trace(&self, _: Params) -> Result; /// Returns all traces of given transaction. - fn transaction_traces(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_traces(&self, _: Params) -> Result; /// Returns all traces produced at given block. - fn block_traces(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_traces(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/web3.rs b/rpc/src/v1/traits/web3.rs index c7b21a1a1..335911025 100644 --- a/rpc/src/v1/traits/web3.rs +++ b/rpc/src/v1/traits/web3.rs @@ -21,10 +21,10 @@ use jsonrpc_core::*; /// Web3 rpc interface. pub trait Web3: Sized + Send + Sync + 'static { /// Returns current client version. - fn client_version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn client_version(&self, _: Params) -> Result; /// Returns sha3 of the given data - fn sha3(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sha3(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { From 191bae5cd47a1804a96b216fc61511239f37c05f Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 28 May 2016 15:25:37 +0200 Subject: [PATCH 34/88] add stubs for missing eth_* rpc methods --- rpc/src/v1/impls/eth.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7627dd61e..026459d9f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -494,6 +494,16 @@ impl Eth for EthClient where }) } + fn sign(&self, params: Params) -> Result { + from_params::<(Address, Bytes)>(params).and_then(|(addr, data)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&addr) { + Ok(secret) => rpc_unimplemented!(), + Err(_) => rpc_unimplemented!(), + } + }) + } + fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) .and_then(|(request, )| { @@ -542,6 +552,18 @@ impl Eth for EthClient where to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))) }) } + + fn compile_lll(&self, _: params) -> Result { + rpc_unimplemented!() + } + + fn compile_serpent(&self, _: params) -> Result { + rpc_unimplemented!() + } + + fn compile_solidity(&self, _: params) -> Result { + rpc_unimplemented!() + } } /// Eth filter rpc implementation. From 7cea3eb5ed8757e816ad4afb6590fb7748ed51c9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 14:53:50 +0200 Subject: [PATCH 35/88] move rpc_unimplemented into impls module --- rpc/src/v1/impls/mod.rs | 4 ++++ rpc/src/v1/traits/mod.rs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index b79772103..94b4fecc1 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -25,6 +25,10 @@ macro_rules! take_weak { } } +macro_rules! rpc_unimplemented { + () => (Err(Error::internal_error())) +} + mod web3; mod eth; mod net; diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index bebf95bb7..0728fd06a 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -16,10 +16,6 @@ //! Ethereum rpc interfaces. -macro_rules! rpc_unimplemented { - () => (Err(Error::internal_error())) -} - pub mod web3; pub mod eth; pub mod net; From be1ec93271b5cefd9f4dd3c39d4b35c21da89b83 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 15:46:57 +0200 Subject: [PATCH 36/88] implement eth_sign --- rpc/src/v1/impls/eth.rs | 16 ++++++---------- rpc/src/v1/tests/eth.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 30 +++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 026459d9f..100770ae1 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -27,6 +27,7 @@ use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; use util::rlp::{encode, decode, UntrustedRlp, View}; +use util::keys::store::AccountProvider; use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID}; use ethcore::block::IsBlock; use ethcore::views::*; @@ -39,7 +40,6 @@ use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager}; use v1::impls::{dispatch_transaction, sign_and_dispatch}; -use util::keys::store::AccountProvider; use serde; /// Eth rpc implementation. @@ -495,12 +495,8 @@ impl Eth for EthClient where } fn sign(&self, params: Params) -> Result { - from_params::<(Address, Bytes)>(params).and_then(|(addr, data)| { - let accounts = take_weak!(self.accounts); - match accounts.account_secret(&addr) { - Ok(secret) => rpc_unimplemented!(), - Err(_) => rpc_unimplemented!(), - } + from_params::<(Address, H256)>(params).and_then(|(addr, msg)| { + to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero())) }) } @@ -553,15 +549,15 @@ impl Eth for EthClient where }) } - fn compile_lll(&self, _: params) -> Result { + fn compile_lll(&self, _: Params) -> Result { rpc_unimplemented!() } - fn compile_serpent(&self, _: params) -> Result { + fn compile_serpent(&self, _: Params) -> Result { rpc_unimplemented!() } - fn compile_solidity(&self, _: params) -> Result { + fn compile_solidity(&self, _: Params) -> Result { rpc_unimplemented!() } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index eac5bafcb..80a856aca 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -27,7 +27,7 @@ use ethcore::transaction::{Transaction, Action}; use ethminer::{MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; -use util::hash::{Address, FixedHash}; +use util::hash::Address; use util::numbers::{Uint, U256}; use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 32a2cd99a..9f6f9881f 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -20,7 +20,7 @@ use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; use util::hash::{Address, H256, FixedHash}; use util::numbers::{Uint, U256}; -use util::keys::{TestAccount, TestAccountProvider}; +use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID}; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; @@ -129,6 +129,28 @@ fn rpc_eth_submit_hashrate() { Some(U256::from(0x500_000))); } +#[test] +fn rpc_eth_sign() { + let tester = EthTester::default(); + + let account = tester.accounts_provider.new_account("abcd").unwrap(); + let message = H256::from("0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f"); + let signed = tester.accounts_provider.sign(&account, &message).unwrap(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_sign", + "params": [ + ""#.to_owned() + &format!("0x{:?}", account) + r#"", + "0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f" + ], + "id": 1 + }"#; + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", signed) + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(&req), Some(res)); +} + #[test] #[ignore] fn rpc_eth_author() { @@ -527,12 +549,6 @@ fn rpc_eth_send_raw_transaction() { unimplemented!() } -#[test] -#[ignore] -fn rpc_eth_sign() { - unimplemented!() -} - #[test] fn rpc_eth_transaction_receipt() { let receipt = LocalizedReceipt { From 89659606dd9a98ccbef87db96d63439ea388de1c Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 17:07:39 +0200 Subject: [PATCH 37/88] add mocked test for eth_sendRawTransaction --- rpc/src/v1/impls/mod.rs | 22 ++++++----------- rpc/src/v1/tests/mocked/eth.rs | 44 ++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 94b4fecc1..7ee8b8b8a 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -59,22 +59,14 @@ fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedT where C: BlockChainClient, M: MinerService { let hash = signed_transaction.hash(); - let import = { - miner.import_own_transaction(client, signed_transaction, |a: &Address| { - AccountDetails { - nonce: client.latest_nonce(&a), - balance: client.latest_balance(&a), - } - }) - }; - - match import { - Ok(_) => to_value(&hash), - Err(e) => { - warn!("Error sending transaction: {:?}", e); - to_value(&H256::zero()) + let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| { + AccountDetails { + nonce: client.latest_nonce(&a), + balance: client.latest_balance(&a), } - } + }); + + to_value(&import.map(|_| hash).unwrap_or(H256::zero())) } fn sign_and_dispatch(client: &Weak, miner: &Weak, request: TransactionRequest, secret: H256) -> Result diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 9f6f9881f..031616450 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -28,6 +28,7 @@ use ethcore::transaction::{Transaction, Action}; use ethminer::ExternalMiner; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; +use rustc_serialize::hex::ToHex; fn blockchain_client() -> Arc { let client = TestBlockChainClient::new(); @@ -215,18 +216,22 @@ fn rpc_eth_balance() { assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } -#[ignore] //TODO: propert test #[test] fn rpc_eth_balance_pending() { let tester = EthTester::default(); + tester.client.set_balance(Address::from(1), U256::from(5)); let request = r#"{ "jsonrpc": "2.0", "method": "eth_getBalance", - "params": ["0x0000000000000000000000000000000000000001", "latest"], + "params": ["0x0000000000000000000000000000000000000001", "pending"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x","id":1}"#; + + // the TestMinerService doesn't communicate with the the TestBlockChainClient in any way. + // if this returns zero, we know that the "pending" call is being properly forwarded to the + // miner. + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } @@ -525,7 +530,7 @@ fn rpc_eth_send_transaction() { let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; - assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); + assert_eq!(tester.io.handle_request(&request), Some(response)); tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero()); @@ -540,13 +545,38 @@ fn rpc_eth_send_transaction() { let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; - assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); + assert_eq!(tester.io.handle_request(&request), Some(response)); } #[test] -#[ignore] fn rpc_eth_send_raw_transaction() { - unimplemented!() + let tester = EthTester::default(); + let address = tester.accounts_provider.new_account("abcd").unwrap(); + let secret = tester.accounts_provider.account_secret(&address).unwrap(); + + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.sign(&secret); + + let rlp = ::util::rlp::encode(&t).to_vec().to_hex(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": [ + "0x"#.to_owned() + &rlp + r#"" + ], + "id": 1 + }"#; + + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", t.hash()) + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(&req), Some(res)); } #[test] From bbe6a287f896f327c5eb475cd8444725b50be7c4 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 17:18:37 +0200 Subject: [PATCH 38/88] add mocked test for eth_coinbase --- rpc/src/v1/tests/mocked/eth.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 031616450..06f1d97b3 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -25,7 +25,7 @@ use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, Transaction use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; -use ethminer::ExternalMiner; +use ethminer::{ExternalMiner, MinerService}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use rustc_serialize::hex::ToHex; @@ -153,9 +153,25 @@ fn rpc_eth_sign() { } #[test] -#[ignore] fn rpc_eth_author() { - unimplemented!() + let make_res = |addr| r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", addr) + r#"","id":1}"#; + let tester = EthTester::default(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_coinbase", + "params": [], + "id": 1 + }"#; + + assert_eq!(tester.io.handle_request(req), Some(make_res(Address::zero()))); + + for i in 0..20 { + let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap(); + tester.miner.set_author(addr.clone()); + + assert_eq!(tester.io.handle_request(req), Some(make_res(addr))); + } } #[test] From ea26deaab142f04940076f5087f857b47c50d441 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 12:33:49 +0200 Subject: [PATCH 39/88] mocked test for eth_syncing --- rpc/src/v1/tests/mocked/eth.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 06f1d97b3..aa0955751 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -26,6 +26,7 @@ use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; use ethminer::{ExternalMiner, MinerService}; +use ethsync::SyncState; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use rustc_serialize::hex::ToHex; @@ -93,9 +94,28 @@ fn rpc_eth_protocol_version() { } #[test] -#[ignore] fn rpc_eth_syncing() { - unimplemented!() + let request = r#"{"jsonrpc": "2.0", "method": "eth_syncing", "params": [], "id": 1}"#; + + let tester = EthTester::default(); + + let false_res = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(false_res.to_owned())); + + { + let mut status = tester.sync.status.write().unwrap(); + status.state = SyncState::Blocks; + status.highest_block_number = Some(2500); + + // causes TestBlockChainClient to return 1000 for its best block number. + let mut blocks = tester.client.blocks.write().unwrap(); + for i in 0..1000 { + blocks.insert(H256::from(i), Vec::new()); + } + } + + let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x03e8","highestBlock":"0x09c4","startingBlock":"0x00"},"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(true_res.to_owned())); } #[test] From 16432129b580635ef6c2380c1f916666d975259c Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 13:13:48 +0200 Subject: [PATCH 40/88] move transaction import error warning into miner implementation --- miner/src/miner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 3860a79e6..fc63aec6c 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -395,6 +395,7 @@ impl MinerService for Miner { Err(ref e) => { trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash); trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); + warn!(target: "own_tx", "Error importing transaction: {:?}", e); }, } import From 76bb0729ba7cc1e3d296343d434218f45ed68155 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 30 May 2016 15:38:23 +0200 Subject: [PATCH 41/88] Updated dependencies for windows build --- Cargo.lock | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dff43d04..38c3c45a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,7 +299,7 @@ version = "1.2.0" dependencies = [ "ethcore-devtools 1.2.0", "ethcore-util 1.2.0", - "nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", + "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -321,7 +321,7 @@ dependencies = [ "ethcore-ipc 1.2.0", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", + "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", ] [[package]] @@ -389,7 +389,7 @@ dependencies = [ "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.3 (git+https://github.com/ethcore/rust-rocksdb)", + "rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -659,14 +659,6 @@ name = "libc" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "librocksdb-sys" -version = "0.2.3" -source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1" -dependencies = [ - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.3.6" @@ -742,8 +734,8 @@ dependencies = [ [[package]] name = "nanomsg" -version = "0.5.0" -source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1" +version = "0.5.1" +source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" dependencies = [ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", @@ -752,7 +744,7 @@ dependencies = [ [[package]] name = "nanomsg-sys" version = "0.5.0" -source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1" +source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" dependencies = [ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1073,11 +1065,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.4.3" -source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1" +version = "0.4.5" +source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9" dependencies = [ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.2.3 (git+https://github.com/ethcore/rust-rocksdb)", + "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", +] + +[[package]] +name = "rocksdb-sys" +version = "0.3.0" +source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] From b036f1de98bd82648033d4fc8be5f56aadd95054 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 10:31:36 +0200 Subject: [PATCH 42/88] stop eth_syncing from returning true forever (#1181) --- rpc/src/v1/impls/eth.rs | 6 ++++-- rpc/src/v1/tests/mocked/eth.rs | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 100770ae1..a57fc333c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -244,12 +244,14 @@ impl Eth for EthClient where let res = match status.state { SyncState::Idle => SyncStatus::None, SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => { + let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number); + let info = SyncInfo { starting_block: U256::from(status.start_block_number), - current_block: U256::from(take_weak!(self.client).chain_info().best_block_number), + current_block: current_block, highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number)) }; - match info.highest_block > info.starting_block + U256::from(6) { + match info.highest_block > info.current_block + U256::from(6) { true => SyncStatus::Info(info), false => SyncStatus::None, } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index aa0955751..c51d6d7da 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -107,6 +107,7 @@ fn rpc_eth_syncing() { status.state = SyncState::Blocks; status.highest_block_number = Some(2500); + // "sync" to 1000 blocks. // causes TestBlockChainClient to return 1000 for its best block number. let mut blocks = tester.client.blocks.write().unwrap(); for i in 0..1000 { @@ -116,6 +117,16 @@ fn rpc_eth_syncing() { let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x03e8","highestBlock":"0x09c4","startingBlock":"0x00"},"id":1}"#; assert_eq!(tester.io.handle_request(request), Some(true_res.to_owned())); + + { + // finish "syncing" + let mut blocks = tester.client.blocks.write().unwrap(); + for i in 0..1500 { + blocks.insert(H256::from(i + 1000), Vec::new()); + } + } + + assert_eq!(tester.io.handle_request(request), Some(false_res.to_owned())); } #[test] From d0b32f8d426398297bc5d07d859a27b6e7c5d80b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 13:02:53 +0200 Subject: [PATCH 43/88] trait import from branch --- db/src/traits.rs | 95 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/db/src/traits.rs b/db/src/traits.rs index 1e5b2acf4..dd5743fe5 100644 --- a/db/src/traits.rs +++ b/db/src/traits.rs @@ -1,21 +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 . + //! Ethcore database trait -use ipc::BinaryConvertable; use std::mem; use ipc::binary::BinaryConvertError; use std::collections::VecDeque; +use std::cell::RefCell; -pub type TransactionHandle = u32; pub type IteratorHandle = u32; +pub const DEFAULT_CACHE_LEN: usize = 12288; + #[derive(Binary)] pub struct KeyValue { pub key: Vec, pub value: Vec, } -#[derive(Debug, Binary)] -pub enum Error { + #[derive(Debug, Binary)] + pub enum Error { AlreadyOpen, IsClosed, RocksDb(String), @@ -28,13 +45,36 @@ pub enum Error { #[derive(Binary)] pub struct DatabaseConfig { /// Optional prefix size in bytes. Allows lookup by partial key. - pub prefix_size: Option + pub prefix_size: Option, + /// write cache length + pub cache: usize, } -pub trait DatabaseService { +impl Default for DatabaseConfig { + fn default() -> DatabaseConfig { + DatabaseConfig { + prefix_size: None, + cache: DEFAULT_CACHE_LEN, + } + } +} + +impl DatabaseConfig { + fn with_prefix(prefix: usize) -> DatabaseConfig { + DatabaseConfig { + prefix_size: Some(prefix), + cache: DEFAULT_CACHE_LEN, + } + } +} + + pub trait DatabaseService : Sized { /// Opens database in the specified path fn open(&self, config: DatabaseConfig, path: String) -> Result<(), Error>; + /// Opens database in the specified path with the default config + fn open_default(&self, path: String) -> Result<(), Error>; + /// Closes database fn close(&self) -> Result<(), Error>; @@ -44,18 +84,6 @@ pub trait DatabaseService { /// Delete value by key. fn delete(&self, key: &[u8]) -> Result<(), Error>; - /// Insert a key-value pair in the transaction. Any existing value value will be overwritten. - fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error>; - - /// Delete value by key using transaction - fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error>; - - /// Commit transaction to database. - fn write(&self, tr: TransactionHandle) -> Result<(), Error>; - - /// Initiate new transaction on database - fn new_transaction(&self) -> TransactionHandle; - /// Get value by key. fn get(&self, key: &[u8]) -> Result>, Error>; @@ -70,4 +98,35 @@ pub trait DatabaseService { /// Next key-value for the the given iterator fn iter_next(&self, iterator: IteratorHandle) -> Option; + + /// Dispose iteration that is no longer needed + fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error>; + + /// Write client transaction + fn write(&self, transaction: DBTransaction) -> Result<(), Error>; +} + +#[derive(Binary)] +pub struct DBTransaction { + pub writes: RefCell>, + pub removes: RefCell>>, +} + +impl DBTransaction { + pub fn new() -> DBTransaction { + DBTransaction { + writes: RefCell::new(Vec::new()), + removes: RefCell::new(Vec::new()), + } + } + + pub fn put(&self, key: &[u8], value: &[u8]) { + let mut brw = self.writes.borrow_mut(); + brw.push(KeyValue { key: key.to_vec(), value: value.to_vec() }); + } + + pub fn delete(&self, key: &[u8]) { + let mut brw = self.removes.borrow_mut(); + brw.push(key.to_vec()); + } } From 134f48cdfb211c971fc9db8edf7d150bb8e79ded Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 13:05:43 +0200 Subject: [PATCH 44/88] lib import --- db/src/lib.rs.in | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/db/src/lib.rs.in b/db/src/lib.rs.in index 694b4e3e1..4fa43b977 100644 --- a/db/src/lib.rs.in +++ b/db/src/lib.rs.in @@ -19,7 +19,71 @@ extern crate rocksdb; extern crate ethcore_devtools as devtools; extern crate semver; extern crate ethcore_ipc_nano as nanoipc; +extern crate nanomsg; +extern crate crossbeam; extern crate ethcore_util as util; pub mod database; pub mod traits; + +pub use traits::{DatabaseService, DBTransaction, Error}; +pub use database::{Database, DatabaseClient, DatabaseIterator}; + +use std::sync::Arc; +use std::sync::atomic::*; +use std::path::PathBuf; + +pub type DatabaseNanoClient = DatabaseClient<::nanomsg::Socket>; +pub type DatabaseConnection = nanoipc::GuardedSocket; + +#[derive(Debug)] +pub enum ServiceError { + Io(std::io::Error), + Socket(nanoipc::SocketError), +} + +impl std::convert::From for ServiceError { + fn from(io_error: std::io::Error) -> ServiceError { ServiceError::Io(io_error) } +} + +impl std::convert::From for ServiceError { + fn from(socket_error: nanoipc::SocketError) -> ServiceError { ServiceError::Socket(socket_error) } +} + +pub fn blocks_service_url(db_path: &str) -> Result { + let mut path = PathBuf::from(db_path); + try!(::std::fs::create_dir_all(db_path)); + path.push("blocks.ipc"); + Ok(format!("ipc://{}", path.to_str().unwrap())) +} + +pub fn extras_service_url(db_path: &str) -> Result { + let mut path = PathBuf::from(db_path); + try!(::std::fs::create_dir_all(db_path)); + path.push("extras.ipc"); + Ok(format!("ipc://{}", path.to_str().unwrap())) +} + +pub fn blocks_client(db_path: &str) -> Result { + let url = try!(blocks_service_url(db_path)); + let client = try!(nanoipc::init_client::>(&url)); + Ok(client) +} + +pub fn extras_client(db_path: &str) -> Result { + let url = try!(extras_service_url(db_path)); + let client = try!(nanoipc::init_client::>(&url)); + Ok(client) +} + +// for tests +pub fn run_worker(scope: &crossbeam::Scope, stop: Arc, socket_path: &str) { + let socket_path = socket_path.to_owned(); + scope.spawn(move || { + let mut worker = nanoipc::Worker::new(&Arc::new(Database::new())); + worker.add_reqrep(&socket_path).unwrap(); + while !stop.load(Ordering::Relaxed) { + worker.poll(); + } + }); +} From 1d5f407a298bf2cdd27730a8558bc9e45d28f3ff Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 13:08:15 +0200 Subject: [PATCH 45/88] database & write que import --- db/src/database.rs | 399 ++++++++++++++++++++++++++++++++++----------- db/src/service.rs | 0 2 files changed, 301 insertions(+), 98 deletions(-) delete mode 100644 db/src/service.rs diff --git a/db/src/database.rs b/db/src/database.rs index 4abc98467..d535f1f56 100644 --- a/db/src/database.rs +++ b/db/src/database.rs @@ -18,15 +18,13 @@ use traits::*; use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBIterator, - IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; -use std::collections::BTreeMap; -use std::sync::{RwLock}; +IndexType, Options, DBCompactionStyle, BlockBasedOptions, Direction}; +use std::sync::{RwLock, Arc}; use std::convert::From; use ipc::IpcConfig; -use std::ops::*; use std::mem; use ipc::binary::BinaryConvertError; -use std::collections::VecDeque; +use std::collections::{VecDeque, HashMap, BTreeMap}; impl From for Error { fn from(s: String) -> Error { @@ -34,20 +32,136 @@ impl From for Error { } } +enum WriteCacheEntry { + Remove, + Write(Vec), +} + +pub struct WriteCache { + entries: HashMap, WriteCacheEntry>, + preferred_len: usize, +} + +const FLUSH_BATCH_SIZE: usize = 4096; + +impl WriteCache { + fn new(cache_len: usize) -> WriteCache { + WriteCache { + entries: HashMap::new(), + preferred_len: cache_len, + } + } + + fn write(&mut self, key: Vec, val: Vec) { + self.entries.insert(key, WriteCacheEntry::Write(val)); + } + + fn remove(&mut self, key: Vec) { + self.entries.insert(key, WriteCacheEntry::Remove); + } + + fn get(&self, key: &Vec) -> Option> { + self.entries.get(key).and_then( + |vec_ref| match vec_ref { + &WriteCacheEntry::Write(ref val) => Some(val.clone()), + &WriteCacheEntry::Remove => None + }) + } + + /// WriteCache should be locked for this + fn flush(&mut self, db: &DB, amount: usize) -> Result<(), Error> { + let batch = WriteBatch::new(); + let mut removed_so_far = 0; + while removed_so_far < amount { + if self.entries.len() == 0 { break; } + let removed_key = { + let (key, cache_entry) = self.entries.iter().nth(0) + .expect("if entries.len == 0, we should have break in the loop, still we got here somehow"); + + match *cache_entry { + WriteCacheEntry::Write(ref val) => { + try!(batch.put(&key, val)); + }, + WriteCacheEntry::Remove => { + try!(batch.delete(&key)); + }, + } + key.clone() + }; + + self.entries.remove(&removed_key); + + removed_so_far = removed_so_far + 1; + } + if removed_so_far > 0 { + try!(db.write(batch)); + } + Ok(()) + } + + /// flushes until cache is empty + fn flush_all(&mut self, db: &DB) -> Result<(), Error> { + while !self.is_empty() { try!(self.flush(db, FLUSH_BATCH_SIZE)); } + Ok(()) + } + + fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + fn try_shrink(&mut self, db: &DB) -> Result<(), Error> { + if self.entries.len() > self.preferred_len { + try!(self.flush(db, FLUSH_BATCH_SIZE)); + } + Ok(()) + } +} + pub struct Database { db: RwLock>, - transactions: RwLock>, + /// Iterators - dont't use between threads! iterators: RwLock>, + write_cache: RwLock, } +unsafe impl Send for Database {} +unsafe impl Sync for Database {} + impl Database { pub fn new() -> Database { Database { db: RwLock::new(None), - transactions: RwLock::new(BTreeMap::new()), iterators: RwLock::new(BTreeMap::new()), + write_cache: RwLock::new(WriteCache::new(DEFAULT_CACHE_LEN)), } } + + pub fn flush(&self) -> Result<(), Error> { + let mut cache_lock = self.write_cache.write().unwrap(); + let db_lock = self.db.read().unwrap(); + if db_lock.is_none() { return Ok(()); } + let db = db_lock.as_ref().unwrap(); + + try!(cache_lock.try_shrink(&db)); + Ok(()) + } + + pub fn flush_all(&self) -> Result<(), Error> { + let mut cache_lock = self.write_cache.write().unwrap(); + let db_lock = self.db.read().unwrap(); + if db_lock.is_none() { return Ok(()); } + let db = db_lock.as_ref().expect("we should have exited with Ok(()) on the previous step"); + + try!(cache_lock.flush_all(&db)); + Ok(()) + + } +} + +impl Drop for Database { + fn drop(&mut self) { + self.flush().unwrap(); + } } #[derive(Ipc)] @@ -72,51 +186,64 @@ impl DatabaseService for Database { Ok(()) } + /// Opens database in the specified path with the default config + fn open_default(&self, path: String) -> Result<(), Error> { + self.open(DatabaseConfig::default(), path) + } + fn close(&self) -> Result<(), Error> { + try!(self.flush_all()); + let mut db = self.db.write().unwrap(); if db.is_none() { return Err(Error::IsClosed); } - // TODO: wait for transactions to expire/close here? - if self.transactions.read().unwrap().len() > 0 { return Err(Error::UncommitedTransactions); } - *db = None; Ok(()) } fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { - let db_lock = self.db.read().unwrap(); - let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); - - try!(db.put(key, value)); + let mut cache_lock = self.write_cache.write().unwrap(); + cache_lock.write(key.to_vec(), value.to_vec()); Ok(()) } fn delete(&self, key: &[u8]) -> Result<(), Error> { - let db_lock = self.db.read().unwrap(); - let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); - - try!(db.delete(key)); + let mut cache_lock = self.write_cache.write().unwrap(); + cache_lock.remove(key.to_vec()); Ok(()) } - fn write(&self, handle: TransactionHandle) -> Result<(), Error> { - let db_lock = self.db.read().unwrap(); - let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); + fn write(&self, transaction: DBTransaction) -> Result<(), Error> { + let mut cache_lock = self.write_cache.write().unwrap(); - let mut transactions = self.transactions.write().unwrap(); - let batch = try!( - transactions.remove(&handle).ok_or(Error::TransactionUnknown) - ); - try!(db.write(batch)); + let mut writes = transaction.writes.borrow_mut(); + for kv in writes.drain(..) { + cache_lock.write(kv.key, kv.value); + } + + let mut removes = transaction.removes.borrow_mut(); + for k in removes.drain(..) { + cache_lock.remove(k); + } Ok(()) } fn get(&self, key: &[u8]) -> Result>, Error> { + { + let key_vec = key.to_vec(); + let cache_hit = self.write_cache.read().unwrap().get(&key_vec); + + if cache_hit.is_some() { + return Ok(Some(cache_hit.expect("cache_hit.is_some() = true, still there is none somehow here"))) + } + } let db_lock = self.db.read().unwrap(); let db = try!(db_lock.as_ref().ok_or(Error::IsClosed)); match try!(db.get(key)) { - Some(db_vec) => Ok(Some(db_vec.to_vec())), + Some(db_vec) => { + Ok(Some(db_vec.to_vec())) + }, None => Ok(None), } } @@ -166,37 +293,35 @@ impl DatabaseService for Database { }) } - fn transaction_put(&self, transaction: TransactionHandle, key: &[u8], value: &[u8]) -> Result<(), Error> - { - let mut transactions = self.transactions.write().unwrap(); - let batch = try!( - transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown) - ); - try!(batch.put(&key, &value)); + fn dispose_iter(&self, handle: IteratorHandle) -> Result<(), Error> { + let mut iterators = self.iterators.write().unwrap(); + iterators.remove(&handle); Ok(()) } - - fn transaction_delete(&self, transaction: TransactionHandle, key: &[u8]) -> Result<(), Error> { - let mut transactions = self.transactions.write().unwrap(); - let batch = try!( - transactions.get_mut(&transaction).ok_or(Error::TransactionUnknown) - ); - try!(batch.delete(&key)); - Ok(()) - } - - fn new_transaction(&self) -> TransactionHandle { - let mut transactions = self.transactions.write().unwrap(); - let next_transaction = transactions.keys().last().unwrap_or(&0) + 1; - transactions.insert(next_transaction, WriteBatch::new()); - - next_transaction - } } // TODO : put proper at compile-time impl IpcConfig for Database {} +/// Database iterator +pub struct DatabaseIterator { + client: Arc>, + handle: IteratorHandle, +} + +impl Iterator for DatabaseIterator { + type Item = (Vec, Vec); + + fn next(&mut self) -> Option { + self.client.iter_next(self.handle).and_then(|kv| Some((kv.key, kv.value))) + } +} + +impl Drop for DatabaseIterator { + fn drop(&mut self) { + self.client.dispose_iter(self.handle).unwrap(); + } +} #[cfg(test)] mod test { @@ -215,7 +340,7 @@ mod test { fn can_be_open_empty() { let db = Database::new(); let path = RandomTempPath::create_dir(); - db.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); + db.open_default(path.as_str().to_owned()).unwrap(); assert!(db.is_empty().is_ok()); } @@ -224,9 +349,10 @@ mod test { fn can_store_key() { let db = Database::new(); let path = RandomTempPath::create_dir(); - db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); + db.open_default(path.as_str().to_owned()).unwrap(); db.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); + db.flush_all().unwrap(); assert!(!db.is_empty().unwrap()); } @@ -234,15 +360,37 @@ mod test { fn can_retrieve() { let db = Database::new(); let path = RandomTempPath::create_dir(); - db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); + db.open_default(path.as_str().to_owned()).unwrap(); db.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); db.close().unwrap(); - db.open(DatabaseConfig { prefix_size: None }, path.as_str().to_owned()).unwrap(); + db.open_default(path.as_str().to_owned()).unwrap(); assert_eq!(db.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec()); } } +#[cfg(test)] +mod write_cache_tests { + use super::Database; + use traits::*; + use devtools::*; + + #[test] + fn cache_write_flush() { + let db = Database::new(); + let path = RandomTempPath::create_dir(); + + db.open_default(path.as_str().to_owned()).unwrap(); + db.put("100500".as_bytes(), "1".as_bytes()).unwrap(); + db.delete("100500".as_bytes()).unwrap(); + db.flush_all().unwrap(); + + let val = db.get("100500".as_bytes()).unwrap(); + assert!(val.is_none()); + } + +} + #[cfg(test)] mod client_tests { use super::{DatabaseClient, Database}; @@ -251,6 +399,8 @@ mod client_tests { use nanoipc; use std::sync::Arc; use std::sync::atomic::{Ordering, AtomicBool}; + use crossbeam; + use run_worker; fn init_worker(addr: &str) -> nanoipc::Worker { let mut worker = nanoipc::Worker::::new(&Arc::new(Database::new())); @@ -268,7 +418,7 @@ mod client_tests { ::std::thread::spawn(move || { let mut worker = init_worker(url); - while !c_worker_should_exit.load(Ordering::Relaxed) { + while !c_worker_should_exit.load(Ordering::Relaxed) { worker.poll(); c_worker_is_ready.store(true, Ordering::Relaxed); } @@ -295,7 +445,7 @@ mod client_tests { ::std::thread::spawn(move || { let mut worker = init_worker(url); - while !c_worker_should_exit.load(Ordering::Relaxed) { + while !c_worker_should_exit.load(Ordering::Relaxed) { worker.poll(); c_worker_is_ready.store(true, Ordering::Relaxed); } @@ -304,7 +454,7 @@ mod client_tests { while !worker_is_ready.load(Ordering::Relaxed) { } let client = nanoipc::init_duplex_client::>(url).unwrap(); - client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); + client.open_default(path.as_str().to_owned()).unwrap(); assert!(client.is_empty().unwrap()); worker_should_exit.store(true, Ordering::Relaxed); } @@ -314,27 +464,16 @@ mod client_tests { let url = "ipc:///tmp/parity-db-ipc-test-30.ipc"; let path = RandomTempPath::create_dir(); - let worker_should_exit = Arc::new(AtomicBool::new(false)); - let worker_is_ready = Arc::new(AtomicBool::new(false)); - let c_worker_should_exit = worker_should_exit.clone(); - let c_worker_is_ready = worker_is_ready.clone(); + crossbeam::scope(move |scope| { + let stop = Arc::new(AtomicBool::new(false)); + run_worker(scope, stop.clone(), url); + let client = nanoipc::init_client::>(url).unwrap(); + client.open_default(path.as_str().to_owned()).unwrap(); + client.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); + client.close().unwrap(); - ::std::thread::spawn(move || { - let mut worker = init_worker(url); - while !c_worker_should_exit.load(Ordering::Relaxed) { - worker.poll(); - c_worker_is_ready.store(true, Ordering::Relaxed); - } + stop.store(true, Ordering::Relaxed); }); - - while !worker_is_ready.load(Ordering::Relaxed) { } - let client = nanoipc::init_duplex_client::>(url).unwrap(); - - client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); - client.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); - client.close().unwrap(); - - worker_should_exit.store(true, Ordering::Relaxed); } #[test] @@ -342,29 +481,93 @@ mod client_tests { let url = "ipc:///tmp/parity-db-ipc-test-40.ipc"; let path = RandomTempPath::create_dir(); - let worker_should_exit = Arc::new(AtomicBool::new(false)); - let worker_is_ready = Arc::new(AtomicBool::new(false)); - let c_worker_should_exit = worker_should_exit.clone(); - let c_worker_is_ready = worker_is_ready.clone(); + crossbeam::scope(move |scope| { + let stop = Arc::new(AtomicBool::new(false)); + run_worker(scope, stop.clone(), url); + let client = nanoipc::init_client::>(url).unwrap(); - ::std::thread::spawn(move || { - let mut worker = init_worker(url); - while !c_worker_should_exit.load(Ordering::Relaxed) { - worker.poll(); - c_worker_is_ready.store(true, Ordering::Relaxed); + client.open_default(path.as_str().to_owned()).unwrap(); + client.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); + client.close().unwrap(); + + client.open_default(path.as_str().to_owned()).unwrap(); + assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec()); + + stop.store(true, Ordering::Relaxed); + }); + } + + #[test] + fn can_read_empty() { + let url = "ipc:///tmp/parity-db-ipc-test-45.ipc"; + let path = RandomTempPath::create_dir(); + + crossbeam::scope(move |scope| { + let stop = Arc::new(AtomicBool::new(false)); + run_worker(scope, stop.clone(), url); + let client = nanoipc::init_client::>(url).unwrap(); + + client.open_default(path.as_str().to_owned()).unwrap(); + assert!(client.get("xxx".as_bytes()).unwrap().is_none()); + + stop.store(true, Ordering::Relaxed); + }); + } + + + #[test] + fn can_commit_client_transaction() { + let url = "ipc:///tmp/parity-db-ipc-test-60.ipc"; + let path = RandomTempPath::create_dir(); + + crossbeam::scope(move |scope| { + let stop = Arc::new(AtomicBool::new(false)); + run_worker(scope, stop.clone(), url); + let client = nanoipc::init_client::>(url).unwrap(); + client.open_default(path.as_str().to_owned()).unwrap(); + + let transaction = DBTransaction::new(); + transaction.put("xxx".as_bytes(), "1".as_bytes()); + client.write(transaction).unwrap(); + + client.close().unwrap(); + + client.open_default(path.as_str().to_owned()).unwrap(); + assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec()); + + stop.store(true, Ordering::Relaxed); + }); + } + + #[test] + fn key_write_read_ipc() { + let url = "ipc:///tmp/parity-db-ipc-test-70.ipc"; + let path = RandomTempPath::create_dir(); + + crossbeam::scope(|scope| { + let stop = StopGuard::new(); + run_worker(&scope, stop.share(), url); + + let client = nanoipc::init_client::>(url).unwrap(); + + client.open_default(path.as_str().to_owned()).unwrap(); + let mut batch = Vec::new(); + for _ in 0..100 { + batch.push((random_str(256).as_bytes().to_vec(), random_str(256).as_bytes().to_vec())); + batch.push((random_str(256).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec())); + batch.push((random_str(2048).as_bytes().to_vec(), random_str(2048).as_bytes().to_vec())); + batch.push((random_str(2048).as_bytes().to_vec(), random_str(256).as_bytes().to_vec())); + } + + for &(ref k, ref v) in batch.iter() { + client.put(k, v).unwrap(); + } + client.close().unwrap(); + + client.open_default(path.as_str().to_owned()).unwrap(); + for &(ref k, ref v) in batch.iter() { + assert_eq!(v, &client.get(k).unwrap().unwrap()); } }); - - while !worker_is_ready.load(Ordering::Relaxed) { } - let client = nanoipc::init_duplex_client::>(url).unwrap(); - - client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); - client.put("xxx".as_bytes(), "1".as_bytes()).unwrap(); - client.close().unwrap(); - - client.open(DatabaseConfig { prefix_size: Some(8) }, path.as_str().to_owned()).unwrap(); - assert_eq!(client.get("xxx".as_bytes()).unwrap().unwrap(), "1".as_bytes().to_vec()); - - worker_should_exit.store(true, Ordering::Relaxed); } } diff --git a/db/src/service.rs b/db/src/service.rs deleted file mode 100644 index e69de29bb..000000000 From a944638b5e51397f6ab439b71fcd93d908c29a84 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 13:17:45 +0200 Subject: [PATCH 46/88] version lock --- db/Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/db/Cargo.toml b/db/Cargo.toml index 8bd26d1f9..24d0e6fbe 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -8,17 +8,19 @@ authors = ["Ethcore "] build = "build.rs" [build-dependencies] -syntex = "*" +syntex = "0.32" ethcore-ipc-codegen = { path = "../ipc/codegen" } [dependencies] -ethcore-util = { path = "../util" } clippy = { version = "0.0.67", optional = true} ethcore-devtools = { path = "../devtools" } ethcore-ipc = { path = "../ipc/rpc" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } semver = "0.2" ethcore-ipc-nano = { path = "../ipc/nano" } +nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } +crossbeam = "0.2" +ethcore-util = { path = "../util" } [features] dev = ["clippy"] From 1465b0d34c3c18abd12602ec66ac74aa188411c5 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 13:10:33 +0200 Subject: [PATCH 47/88] refactor Miner to not wrap accounts in an RwLock, and to take a generalized AccountProvider --- miner/src/miner.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index fc63aec6c..d356a644a 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -18,14 +18,14 @@ use rayon::prelude::*; use std::sync::atomic::AtomicBool; use util::*; -use util::keys::store::{AccountService, AccountProvider}; +use util::keys::store::AccountProvider; use ethcore::views::{BlockView, HeaderView}; use ethcore::client::{BlockChainClient, BlockID}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::error::*; use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions}; use ethcore::transaction::SignedTransaction; -use ethcore::receipt::{Receipt}; +use ethcore::receipt::Receipt; use ethcore::spec::Spec; use ethcore::engine::Engine; use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; @@ -44,7 +44,7 @@ pub struct Miner { extra_data: RwLock, spec: Spec, - accounts: RwLock>>, // TODO: this is horrible since AccountService already contains a single RwLock field. refactor. + accounts: Option>, } impl Default for Miner { @@ -58,7 +58,7 @@ impl Default for Miner { gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), - accounts: RwLock::new(None), + accounts: None, spec: Spec::new_test(), } } @@ -76,13 +76,13 @@ impl Miner { gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), - accounts: RwLock::new(None), + accounts: None, spec: spec, }) } /// Creates new instance of miner - pub fn with_accounts(force_sealing: bool, spec: Spec, accounts: Arc) -> Arc { + pub fn with_accounts(force_sealing: bool, spec: Spec, accounts: Arc) -> Arc { Arc::new(Miner { transaction_queue: Mutex::new(TransactionQueue::new()), force_sealing: force_sealing, @@ -92,7 +92,7 @@ impl Miner { gas_floor_target: RwLock::new(U256::zero()), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), - accounts: RwLock::new(Some(accounts)), + accounts: Some(accounts), spec: spec, }) } @@ -177,9 +177,8 @@ impl Miner { if !block.transactions().is_empty() { trace!(target: "miner", "prepare_sealing: block has transaction - attempting internal seal."); // block with transactions - see if we can seal immediately. - let a = self.accounts.read().unwrap(); - let s = self.engine().generate_seal(block.block(), match *a.deref() { - Some(ref x) => Some(x.deref() as &AccountProvider), + let s = self.engine().generate_seal(block.block(), match self.accounts { + Some(ref x) => Some(&**x), None => None, }); if let Some(seal) = s { From 266b4eedaad7d3a9dda7094bf8a7f91341024141 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 17:42:42 +0200 Subject: [PATCH 48/88] correct locked_account_secret docs --- util/src/keys/store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 3ecabc07c..cf5b2a61e 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -87,7 +87,7 @@ struct AccountUnlock { } /// Basic account management trait -pub trait AccountProvider : Send + Sync { +pub trait AccountProvider: Send + Sync { /// Lists all accounts fn accounts(&self) -> Result, ::std::io::Error>; /// Unlocks account with the password provided @@ -325,7 +325,7 @@ impl SecretStore { ret } - /// Returns secret for unlocked account. + /// Returns secret for locked account. pub fn locked_account_secret(&self, account: &Address, pass: &str) -> Result { let secret_id = try!(self.account(&account).ok_or(SigningError::NoAccount)); self.get(&secret_id, pass).or_else(|e| Err(match e { From 5cb58c42694cd1350a18dec3c169f0d34ce89447 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 20:06:10 +0200 Subject: [PATCH 49/88] use Miner in rpc tests, remove chain_harness --- rpc/src/v1/tests/eth.rs | 371 ++++++++++++++++++++++------------------ 1 file changed, 208 insertions(+), 163 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 80a856aca..9b2cb3195 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,12 +19,11 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; -use ethcore::client::{BlockChainClient, Client, ClientConfig}; -use ethcore::spec::Genesis; +use ethcore::client::{Client, BlockChainClient, ClientConfig}; +use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::ethereum; -use ethcore::transaction::{Transaction, Action}; -use ethminer::{MinerService, ExternalMiner}; +use ethminer::{Miner, MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; use util::hash::Address; @@ -35,135 +34,7 @@ use ethjson::blockchain::BlockChain; use v1::traits::eth::Eth; use v1::impls::EthClient; -use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; - -struct EthTester { - _client: Arc, - _miner: Arc, - accounts: Arc, - handler: IoHandler, -} - -#[test] -fn harness_works() { - let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); - chain_harness(chain, |_| {}); -} - -#[test] -fn eth_get_balance() { - let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); - chain_harness(chain, |tester| { - // final account state - let req_latest = r#"{ - "jsonrpc": "2.0", - "method": "eth_getBalance", - "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], - "id": 1 - }"#; - let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned(); - assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest); - - // non-existant account - let req_new_acc = r#"{ - "jsonrpc": "2.0", - "method": "eth_getBalance", - "params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], - "id": 3 - }"#; - - let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned(); - assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc); - }); -} - -#[test] -fn eth_block_number() { - let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); - chain_harness(chain, |tester| { - let req_number = r#"{ - "jsonrpc": "2.0", - "method": "eth_blockNumber", - "params": [], - "id": 1 - }"#; - - let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned(); - assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number); - }); -} - -#[cfg(test)] -#[test] -fn eth_transaction_count() { - let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); - chain_harness(chain, |tester| { - let address = tester.accounts.new_account("123").unwrap(); - let secret = tester.accounts.account_secret(&address).unwrap(); - - let req_before = r#"{ - "jsonrpc": "2.0", - "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], - "id": 15 - }"#; - - let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; - - assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); - - let t = Transaction { - nonce: U256::zero(), - gas_price: U256::from(0x9184e72a000u64), - gas: U256::from(0x76c0), - action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), - value: U256::from(0x9184e72au64), - data: vec![] - }.sign(&secret); - - let req_send_trans = r#"{ - "jsonrpc": "2.0", - "method": "eth_sendTransaction", - "params": [{ - "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", - "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", - "gas": "0x76c0", - "gasPrice": "0x9184e72a000", - "value": "0x9184e72a" - }], - "id": 16 - }"#; - - let res_send_trans = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":16}"#; - - // dispatch the transaction. - assert_eq!(tester.handler.handle_request(&req_send_trans).unwrap(), res_send_trans); - - // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. - let req_after_latest = r#"{ - "jsonrpc": "2.0", - "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], - "id": 17 - }"#; - - let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#; - - assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest); - - // the pending transactions should have been updated. - let req_after_pending = r#"{ - "jsonrpc": "2.0", - "method": "eth_getTransactionCount", - "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"], - "id": 18 - }"#; - - let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#; - - assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending); - }); -} +use v1::tests::helpers::{TestSyncProvider, Config}; fn account_provider() -> Arc { let mut accounts = HashMap::new(); @@ -179,51 +50,225 @@ fn sync_provider() -> Arc { })) } -fn miner_service() -> Arc { - Arc::new(TestMinerService::default()) +fn miner_service(spec: Spec, accounts: Arc) -> Arc { + Miner::with_accounts(true, spec, accounts) } -// given a blockchain, this harness will create an EthClient wrapping it -// which tests can pass specially crafted requests to. -fn chain_harness(chain: BlockChain, mut cb: F) -> U - where F: FnMut(&EthTester) -> U { +fn make_spec(chain: &BlockChain) -> Spec { let genesis = Genesis::from(chain.genesis()); let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); spec.set_genesis_state(state); spec.overwrite_genesis_params(genesis); assert!(spec.is_state_root_valid()); + spec +} - let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), spec, dir.as_path(), IoChannel::disconnected()).unwrap(); - let sync_provider = sync_provider(); - let miner_service = miner_service(); - let account_provider = account_provider(); - let external_miner = Arc::new(ExternalMiner::default()); +struct EthTester { + _miner: Arc, + client: Arc, + accounts: Arc, + handler: IoHandler, +} - for b in &chain.blocks_rlp() { - if Block::is_good(&b) { - let _ = client.import_block(b.clone()); - client.flush_queue(); - client.import_verified_blocks(&IoChannel::disconnected()); +impl EthTester { + fn from_chain(chain: BlockChain) -> Self { + let tester = Self::from_spec_provider(|| make_spec(&chain)); + + for b in &chain.blocks_rlp() { + if Block::is_good(&b) { + let _ = tester.client.import_block(b.clone()); + tester.client.flush_queue(); + tester.client.import_verified_blocks(&IoChannel::disconnected()); + } } + + assert!(tester.client.chain_info().best_block_hash == chain.best_block.into()); + tester } - assert!(client.chain_info().best_block_hash == chain.best_block.into()); + fn from_spec_provider(spec_provider: F) -> Self + where F: Fn() -> Spec { - let eth_client = EthClient::new(&client, &sync_provider, &account_provider, - &miner_service, &external_miner); + let dir = RandomTempPath::new(); + let client = Client::new(ClientConfig::default(), spec_provider(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let sync_provider = sync_provider(); + let account_provider = account_provider(); + let miner_service = miner_service(spec_provider(), account_provider.clone()); + let external_miner = Arc::new(ExternalMiner::default()); - let handler = IoHandler::new(); - let delegate = eth_client.to_delegate(); - handler.add_delegate(delegate); + let eth_client = EthClient::new(&client, &sync_provider, &account_provider, + &miner_service, &external_miner); - let tester = EthTester { - _miner: miner_service, - _client: client, - accounts: account_provider, - handler: handler, - }; + let handler = IoHandler::new(); + let delegate = eth_client.to_delegate(); + handler.add_delegate(delegate); - cb(&tester) + EthTester { + _miner: miner_service, + client: client, + accounts: account_provider, + handler: handler, + } + } } + +#[test] +fn harness_works() { + let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); + let _ = EthTester::from_chain(chain); +} + +#[test] +fn eth_get_balance() { + let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); + let tester = EthTester::from_chain(chain); + // final account state + let req_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], + "id": 1 + }"#; + let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest); + + // non-existant account + let req_new_acc = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], + "id": 3 + }"#; + + let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc); +} + +#[test] +fn eth_block_number() { + let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); + let tester = EthTester::from_chain(chain); + let req_number = r#"{ + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": [], + "id": 1 + }"#; + + let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number); +} + +// a frontier-like test with an expanded gas limit and balance on known account. +const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{ + "name": "Frontier (Test)", + "engine": { + "Ethash": { + "params": { + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "frontierCompatibilityModeLimit": "0xffffffffffffffff" + } + } + }, + "params": { + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x50000", + "networkID" : "0x1" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x50000" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "faa34835af5c2ea724333018a515fbb7d5bc0b33": { "balance": "10000000000000", "nonce": "0" } + } +} +"#; + +#[cfg(test)] +#[test] +fn eth_transaction_count() { + use util::crypto::Secret; + + let address = Address::from_str("faa34835af5c2ea724333018a515fbb7d5bc0b33").unwrap(); + let secret = Secret::from_str("8a283037bb19c4fed7b1c569e40c7dcff366165eb869110a1b11532963eb9cb2").unwrap(); + + let tester = EthTester::from_spec_provider(|| Spec::load(TRANSACTION_COUNT_SPEC)); + tester.accounts.accounts.write().unwrap().insert(address, TestAccount { + unlocked: false, + password: "123".into(), + secret: secret + }); + + let req_before = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 15 + }"#; + + let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; + + assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); + + let req_send_trans = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x30000", + "gasPrice": "0x01", + "value": "0x9184e72a" + }], + "id": 16 + }"#; + + // dispatch the transaction. + tester.handler.handle_request(&req_send_trans).unwrap(); + + // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. + let req_after_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 17 + }"#; + + let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest); + + // the pending transactions should have been updated. + let req_after_pending = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"], + "id": 18 + }"#; + + let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending); +} \ No newline at end of file From b729a381f8f926786dbe4d6a92bd50c6566eb0a1 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 16:29:53 +0200 Subject: [PATCH 50/88] rewrite map macros not to use an intermediate allocation --- util/src/common.rs | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/util/src/common.rs b/util/src/common.rs index a4ba41f82..7ed660f29 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -26,30 +26,46 @@ pub use sha3::*; #[macro_export] macro_rules! hash_map { - ( $( $x:expr => $y:expr ),* ) => { - vec![ $( ($x, $y) ),* ].into_iter().collect::>() - } + ( $( $x:expr => $y:expr ),* ) => {{ + let mut x = HashMap::new(); + $( + x.insert($x, $y); + )* + x + }} } #[macro_export] macro_rules! hash_mapx { - ( $( $x:expr => $y:expr ),* ) => { - vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::>() - } + ( $( $x:expr => $y:expr ),* ) => {{ + let mut x = HashMap::new(); + $( + x.insert($x.into(), $y.into()); + )* + x + }} } #[macro_export] macro_rules! map { - ( $( $x:expr => $y:expr ),* ) => { - vec![ $( ($x, $y) ),* ].into_iter().collect::>() - } + ( $( $x:expr => $y:expr ),* ) => {{ + let mut x = BTreeMap::new(); + $( + x.insert($x, $y); + )* + x + }} } #[macro_export] macro_rules! mapx { - ( $( $x:expr => $y:expr ),* ) => { - vec![ $( ( From::from($x), From::from($y) ) ),* ].into_iter().collect::>() - } + ( $( $x:expr => $y:expr ),* ) => {{ + let mut x = BTreeMap::new(); + $( + x.insert($x.into(), $y.into()); + )* + x + }} } #[macro_export] From 3788b3a149614a3d61cb72d0a3fb41e3f6221c0a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 16:40:48 +0200 Subject: [PATCH 51/88] expunge x! from util --- util/src/hash.rs | 2 +- util/src/json_aid.rs | 2 +- util/src/keys/store.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/hash.rs b/util/src/hash.rs index ba96f812c..1a16cefa4 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -718,7 +718,7 @@ mod tests { #[test] fn from_and_to_u256() { - let u: U256 = x!(0x123456789abcdef0u64); + let u: U256 = 0x123456789abcdef0u64.into(); let h = H256::from(u); assert_eq!(H256::from(u), H256::from("000000000000000000000000000000000000000000000000123456789abcdef0")); let h_ref = H256::from(&u); diff --git a/util/src/json_aid.rs b/util/src/json_aid.rs index 6aed7f09c..7bf940b99 100644 --- a/util/src/json_aid.rs +++ b/util/src/json_aid.rs @@ -48,7 +48,7 @@ impl FromJson for Bytes { impl FromJson for BTreeMap { fn from_json(json: &Json) -> Self { match *json { - Json::Object(ref o) => o.iter().map(|(key, value)| (x!(&u256_from_str(key)), x!(&U256::from_json(value)))).collect(), + Json::Object(ref o) => o.iter().map(|(key, value)| (u256_from_str(key).into(), U256::from_json(value).into())).collect(), _ => BTreeMap::new(), } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 3ecabc07c..296f7ad37 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -554,7 +554,7 @@ mod tests { H256::from_str("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2").unwrap(), 262144, 32)); - key_file.account = Some(x!(i as u64)); + key_file.account = Some((i as u64).into()); result.push(key_file.id.clone()); write_sstore.import_key(key_file).unwrap(); } From 0cd864429202cdf50c8f2f51538c4bcf2a079d49 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 16:41:15 +0200 Subject: [PATCH 52/88] split interfaces --- ethcore/src/client/client.rs | 146 +++++++++++++++--------------- ethcore/src/client/mod.rs | 20 ++-- ethcore/src/client/test_client.rs | 21 +++-- miner/src/lib.rs | 24 ++--- miner/src/miner.rs | 34 +++---- 5 files changed, 126 insertions(+), 119 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ab1c21af1..8f6d607ba 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,7 +37,7 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; -use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, TraceFilter}; +use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, ExtendedBlockChainClient, TraceFilter}; use client::Error as ClientError; use env_info::EnvInfo; use executive::{Executive, Executed, TransactOptions, contract_address}; @@ -448,81 +448,10 @@ impl BlockChainClient for Client where V: Verifier { Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options) } - // TODO [todr] Should be moved to miner crate eventually. - fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result { - block.try_seal(self.engine.deref().deref(), seal) - } - fn vm_factory(&self) -> &EvmFactory { &self.vm_factory } - // TODO [todr] Should be moved to miner crate eventually. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) - -> (Option, HashSet) { - let engine = self.engine.deref().deref(); - let h = self.chain.best_block_hash(); - let mut invalid_transactions = HashSet::new(); - - let mut b = OpenBlock::new( - engine, - &self.vm_factory, - false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. - self.state_db.lock().unwrap().boxed_clone(), - match self.chain.block_header(&h) { Some(ref x) => x, None => { return (None, invalid_transactions) } }, - self.build_last_hashes(h.clone()), - author, - gas_floor_target, - extra_data, - ); - - // Add uncles - self.chain - .find_uncle_headers(&h, engine.maximum_uncle_age()) - .unwrap() - .into_iter() - .take(engine.maximum_uncle_count()) - .foreach(|h| { - b.push_uncle(h).unwrap(); - }); - - // Add transactions - let block_number = b.block().header().number(); - let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas); - - for tx in transactions { - // Push transaction to block - let hash = tx.hash(); - let import = b.push_transaction(tx, None); - - match import { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { - trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); - // Exit early if gas left is smaller then min_tx_gas - if gas_limit - gas_used < min_tx_gas { - break; - } - }, - Err(e) => { - invalid_transactions.insert(hash); - trace!(target: "miner", - "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", - block_number, hash, e); - }, - _ => {} - } - } - - // And close - let b = b.close(); - trace!(target: "miner", "Sealing: number={}, hash={}, diff={}", - b.block().header().number(), - b.hash(), - b.block().header().difficulty() - ); - (Some(b), invalid_transactions) - } - fn block_header(&self, id: BlockID) -> Option { Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) } @@ -776,6 +705,79 @@ impl BlockChainClient for Client where V: Verifier { } } +impl ExtendedBlockChainClient for Client where V: Verifier { + // TODO [todr] Should be moved to miner crate eventually. + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> (Option, HashSet) { + let engine = self.engine.deref().deref(); + let h = self.chain.best_block_hash(); + let mut invalid_transactions = HashSet::new(); + + let mut b = OpenBlock::new( + engine, + &self.vm_factory, + false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. + self.state_db.lock().unwrap().boxed_clone(), + match self.chain.block_header(&h) { Some(ref x) => x, None => { return (None, invalid_transactions) } }, + self.build_last_hashes(h.clone()), + author, + gas_floor_target, + extra_data, + ); + + // Add uncles + self.chain + .find_uncle_headers(&h, engine.maximum_uncle_age()) + .unwrap() + .into_iter() + .take(engine.maximum_uncle_count()) + .foreach(|h| { + b.push_uncle(h).unwrap(); + }); + + // Add transactions + let block_number = b.block().header().number(); + let min_tx_gas = U256::from(self.engine.schedule(&b.env_info()).tx_gas); + + for tx in transactions { + // Push transaction to block + let hash = tx.hash(); + let import = b.push_transaction(tx, None); + + match import { + Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { + trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + // Exit early if gas left is smaller then min_tx_gas + if gas_limit - gas_used < min_tx_gas { + break; + } + }, + Err(e) => { + invalid_transactions.insert(hash); + trace!(target: "miner", + "Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?}", + block_number, hash, e); + }, + _ => {} + } + } + + // And close + let b = b.close(); + trace!(target: "miner", "Sealing: number={}, hash={}, diff={}", + b.block().header().number(), + b.hash(), + b.block().header().difficulty() + ); + (Some(b), invalid_transactions) + } + + // TODO [todr] Should be moved to miner crate eventually. + fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result { + block.try_seal(self.engine.deref().deref(), seal) + } +} + impl MayPanic for Client { fn on_panic(&self, closure: F) where F: OnPanicListener { self.panic_handler.on_panic(closure); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 8e0a7b2dd..5537f8e66 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -154,15 +154,6 @@ pub trait BlockChainClient : Sync + Send { /// Returns logs matching given filter. fn logs(&self, filter: Filter) -> Vec; - // TODO [todr] Should be moved to miner crate eventually. - /// Returns ClosedBlock prepared for sealing. - fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) - -> (Option, HashSet); - - // TODO [todr] Should be moved to miner crate eventually. - /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. - fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; - /// Makes a non-persistent transaction call. fn call(&self, t: &SignedTransaction) -> Result; @@ -185,3 +176,14 @@ pub trait BlockChainClient : Sync + Send { fn last_hashes(&self) -> LastHashes; } +/// Extended client interface used for mining +pub trait ExtendedBlockChainClient : BlockChainClient { + // TODO [todr] Should be moved to miner crate eventually. + /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. + fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; + + // TODO [todr] Should be moved to miner crate eventually. + /// Returns ClosedBlock prepared for sealing. + fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) + -> (Option, HashSet); +} diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index de2973029..5c093b720 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; -use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes}; +use client::{BlockChainClient, ExtendedBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -232,6 +232,17 @@ impl TestBlockChainClient { } } +impl ExtendedBlockChainClient for TestBlockChainClient { + fn try_seal(&self, block: LockedBlock, _seal: Vec) -> Result { + Err(block) + } + + + fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> (Option, HashSet) { + (None, HashSet::new()) + } +} + impl BlockChainClient for TestBlockChainClient { fn call(&self, _t: &SignedTransaction) -> Result { Ok(self.execution_result.read().unwrap().clone().unwrap()) @@ -296,14 +307,6 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn prepare_sealing(&self, _author: Address, _gas_floor_target: U256, _extra_data: Bytes, _transactions: Vec) -> (Option, HashSet) { - (None, HashSet::new()) - } - - fn try_seal(&self, block: LockedBlock, _seal: Vec) -> Result { - Err(block) - } - fn block_header(&self, id: BlockID) -> Option { self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a1780efff..db3315376 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -62,7 +62,7 @@ pub use external::{ExternalMiner, ExternalMinerService}; use std::collections::BTreeMap; use util::{H256, U256, Address, Bytes}; -use ethcore::client::{BlockChainClient, Executed}; +use ethcore::client::{ExtendedBlockChainClient, Executed}; use ethcore::block::ClosedBlock; use ethcore::receipt::Receipt; use ethcore::error::{Error, ExecutionError}; @@ -110,7 +110,7 @@ pub trait MinerService : Send + Sync { where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Imports own (node owner) transaction to queue. - fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> + fn import_own_transaction(&self, chain: &ExtendedBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails, Self: Sized; @@ -118,20 +118,20 @@ pub trait MinerService : Send + Sync { fn pending_transactions_hashes(&self) -> Vec; /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, chain: &BlockChainClient); + fn clear_and_reset(&self, chain: &ExtendedBlockChainClient); /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); + fn chain_new_blocks(&self, chain: &ExtendedBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. - fn update_sealing(&self, chain: &BlockChainClient); + fn update_sealing(&self, chain: &ExtendedBlockChainClient); /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; + fn submit_seal(&self, chain: &ExtendedBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option + fn map_sealing_work(&self, chain: &ExtendedBlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T, Self: Sized; /// Query pending transactions for hash. @@ -156,19 +156,19 @@ pub trait MinerService : Send + Sync { fn sensible_gas_limit(&self) -> U256 { x!(21000) } /// Latest account balance in pending state. - fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256; + fn balance(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256; /// Call into contract code using pending state. - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result; + fn call(&self, chain: &ExtendedBlockChainClient, t: &SignedTransaction) -> Result; /// Get storage value in pending state. - fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256; + fn storage_at(&self, chain: &ExtendedBlockChainClient, address: &Address, position: &H256) -> H256; /// Get account nonce in pending state. - fn nonce(&self, chain: &BlockChainClient, address: &Address) -> U256; + fn nonce(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256; /// Get contract code in pending state. - fn code(&self, chain: &BlockChainClient, address: &Address) -> Option; + fn code(&self, chain: &ExtendedBlockChainClient, address: &Address) -> Option; } /// Mining status diff --git a/miner/src/miner.rs b/miner/src/miner.rs index fc63aec6c..7438e7e9b 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -20,7 +20,7 @@ use std::sync::atomic::AtomicBool; use util::*; use util::keys::store::{AccountService, AccountProvider}; use ethcore::views::{BlockView, HeaderView}; -use ethcore::client::{BlockChainClient, BlockID}; +use ethcore::client::{ExtendedBlockChainClient, BlockID}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::error::*; use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions}; @@ -104,7 +104,7 @@ impl Miner { /// Prepares new block for sealing including top transactions from queue. #[cfg_attr(feature="dev", allow(match_same_arms))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] - fn prepare_sealing(&self, chain: &BlockChainClient) { + fn prepare_sealing(&self, chain: &ExtendedBlockChainClient) { trace!(target: "miner", "prepare_sealing: entering"); let transactions = self.transaction_queue.lock().unwrap().top_transactions(); let mut sealing_work = self.sealing_work.lock().unwrap(); @@ -206,14 +206,14 @@ impl Miner { trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash())); } - fn update_gas_limit(&self, chain: &BlockChainClient) { + fn update_gas_limit(&self, chain: &ExtendedBlockChainClient) { let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); let mut queue = self.transaction_queue.lock().unwrap(); queue.set_gas_limit(gas_limit); } /// Returns true if we had to prepare new pending block - fn enable_and_prepare_sealing(&self, chain: &BlockChainClient) -> bool { + fn enable_and_prepare_sealing(&self, chain: &ExtendedBlockChainClient) -> bool { trace!(target: "miner", "enable_and_prepare_sealing: entering"); let have_work = self.sealing_work.lock().unwrap().peek_last_ref().is_some(); trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work); @@ -237,7 +237,7 @@ const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; impl MinerService for Miner { - fn clear_and_reset(&self, chain: &BlockChainClient) { + fn clear_and_reset(&self, chain: &ExtendedBlockChainClient) { self.transaction_queue.lock().unwrap().clear(); self.update_sealing(chain); } @@ -252,7 +252,7 @@ impl MinerService for Miner { } } - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result { + fn call(&self, chain: &ExtendedBlockChainClient, t: &SignedTransaction) -> Result { let sealing_work = self.sealing_work.lock().unwrap(); match sealing_work.peek_last_ref() { Some(work) => { @@ -288,7 +288,7 @@ impl MinerService for Miner { } } - fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256 { + fn balance(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else( || chain.latest_balance(address), @@ -296,7 +296,7 @@ impl MinerService for Miner { ) } - fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256 { + fn storage_at(&self, chain: &ExtendedBlockChainClient, address: &Address, position: &H256) -> H256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else( || chain.latest_storage_at(address, position), @@ -304,12 +304,12 @@ impl MinerService for Miner { ) } - fn nonce(&self, chain: &BlockChainClient, address: &Address) -> U256 { + fn nonce(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address)) } - fn code(&self, chain: &BlockChainClient, address: &Address) -> Option { + fn code(&self, chain: &ExtendedBlockChainClient, address: &Address) -> Option { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address)) } @@ -376,7 +376,7 @@ impl MinerService for Miner { .collect() } - fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> + fn import_own_transaction(&self, chain: &ExtendedBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails { let hash = transaction.hash(); @@ -470,7 +470,7 @@ impl MinerService for Miner { self.transaction_queue.lock().unwrap().last_nonce(address) } - fn update_sealing(&self, chain: &BlockChainClient) { + fn update_sealing(&self, chain: &ExtendedBlockChainClient) { if self.sealing_enabled.load(atomic::Ordering::Relaxed) { let current_no = chain.chain_info().best_block_number; let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions(); @@ -490,7 +490,7 @@ impl MinerService for Miner { } } - fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { + fn map_sealing_work(&self, chain: &ExtendedBlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { trace!(target: "miner", "map_sealing_work: entering"); self.enable_and_prepare_sealing(chain); trace!(target: "miner", "map_sealing_work: sealing prepared"); @@ -500,7 +500,7 @@ impl MinerService for Miner { ret.map(f) } - fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, chain: &ExtendedBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) { match chain.try_seal(b.lock(), seal) { Err(_) => { @@ -523,8 +523,8 @@ impl MinerService for Miner { } } - fn chain_new_blocks(&self, chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec { + fn chain_new_blocks(&self, chain: &ExtendedBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { + fn fetch_transactions(chain: &ExtendedBlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockID::Hash(*hash)) // Client should send message after commit to db and inserting to chain. @@ -591,7 +591,7 @@ mod tests { use ethcore::client::{TestBlockChainClient, EachBlockWith}; use ethcore::block::*; - // TODO [ToDr] To uncomment when TestBlockChainClient can actually return a ClosedBlock. + // TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock. #[ignore] #[test] fn should_prepare_block_to_seal() { From ff7c755930c35205e80b2a5f48ff3c731d838c83 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 16:59:01 +0200 Subject: [PATCH 53/88] mostly purge x! from ethcore --- ethcore/src/account.rs | 18 +- ethcore/src/account_db.rs | 4 +- ethcore/src/basic_authority.rs | 14 +- ethcore/src/block.rs | 8 +- ethcore/src/block_queue.rs | 6 +- ethcore/src/client/client.rs | 4 +- ethcore/src/env_info.rs | 14 +- ethcore/src/ethereum/ethash.rs | 28 +-- ethcore/src/executive.rs | 20 +- ethcore/src/externalities.rs | 8 +- ethcore/src/pod_account.rs | 38 +-- ethcore/src/state.rs | 414 ++++++++++++++++----------------- ethcore/src/substate.rs | 6 +- ethcore/src/tests/client.rs | 2 +- ethcore/src/tests/helpers.rs | 6 +- ethcore/src/types/receipt.rs | 6 +- 16 files changed, 298 insertions(+), 298 deletions(-) diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 66cceda42..7ba213393 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -261,7 +261,7 @@ mod tests { let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(x!(69), x!(0)); + let mut a = Account::new_contract(69.into(), 0.into()); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); a.commit_storage(&mut db); a.init_code(vec![]); @@ -281,7 +281,7 @@ mod tests { let mut db = AccountDBMut::new(&mut db, &Address::new()); let rlp = { - let mut a = Account::new_contract(x!(69), x!(0)); + let mut a = Account::new_contract(69.into(), 0.into()); a.init_code(vec![0x55, 0x44, 0xffu8]); a.commit_code(&mut db); a.rlp() @@ -296,10 +296,10 @@ mod tests { #[test] fn commit_storage() { - let mut a = Account::new_contract(x!(69), x!(0)); + let mut a = Account::new_contract(69.into(), 0.into()); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.set_storage(x!(0), x!(0x1234)); + a.set_storage(0.into(), 0x1234.into()); assert_eq!(a.storage_root(), None); a.commit_storage(&mut db); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); @@ -307,21 +307,21 @@ mod tests { #[test] fn commit_remove_commit_storage() { - let mut a = Account::new_contract(x!(69), x!(0)); + let mut a = Account::new_contract(69.into(), 0.into()); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.set_storage(x!(0), x!(0x1234)); + a.set_storage(0.into(), 0x1234.into()); a.commit_storage(&mut db); - a.set_storage(x!(1), x!(0x1234)); + a.set_storage(1.into(), 0x1234.into()); a.commit_storage(&mut db); - a.set_storage(x!(1), x!(0)); + a.set_storage(1.into(), 0.into()); a.commit_storage(&mut db); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); } #[test] fn commit_code() { - let mut a = Account::new_contract(x!(69), x!(0)); + let mut a = Account::new_contract(69.into(), 0.into()); let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.init_code(vec![0x55, 0x44, 0xffu8]); diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index f95ec53a1..c21ea2993 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -20,7 +20,7 @@ impl<'db> AccountDB<'db> { pub fn new(db: &'db HashDB, address: &Address) -> AccountDB<'db> { AccountDB { db: db, - address: x!(address), + address: address.into(), } } } @@ -67,7 +67,7 @@ impl<'db> AccountDBMut<'db> { pub fn new(db: &'db mut HashDB, address: &Address) -> AccountDBMut<'db> { AccountDBMut { db: db, - address: x!(address), + address: address.into(), } } diff --git a/ethcore/src/basic_authority.rs b/ethcore/src/basic_authority.rs index fec23cf54..b4a938642 100644 --- a/ethcore/src/basic_authority.rs +++ b/ethcore/src/basic_authority.rs @@ -86,9 +86,9 @@ impl Engine for BasicAuthority { let gas_limit = parent.gas_limit; let bound_divisor = self.our_params.gas_limit_bound_divisor; if gas_limit < gas_floor_target { - min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1)) + min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) } else { - max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1)) + max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) } }; header.note_dirty(); @@ -211,12 +211,12 @@ mod tests { let engine = new_test_authority().engine; let schedule = engine.schedule(&EnvInfo { number: 10000000, - author: x!(0), + author: 0.into(), timestamp: 0, - difficulty: x!(0), + difficulty: 0.into(), last_hashes: vec![], - gas_used: x!(0), - gas_limit: x!(0) + gas_used: 0.into(), + gas_limit: 0.into() }); assert!(schedule.stack_limit > 0); @@ -278,7 +278,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), x!(3141562), vec![]); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]); let b = b.close_and_lock(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 90d4eec2d..0b75f5a7e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -469,7 +469,7 @@ pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Head } } - let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), x!(3141562), header.extra_data().clone()); + let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -514,7 +514,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]); let b = b.close_and_lock(); let _ = b.seal(engine.deref(), vec![]); } @@ -530,7 +530,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -557,7 +557,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), x!(3141562), vec![]); + let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]); let mut uncle1_header = Header::new(); uncle1_header.extra_data = b"uncle1".to_vec(); let mut uncle2_header = Header::new(); diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index bf11f5f1f..5e89641c0 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -311,17 +311,17 @@ impl BlockQueue { let h = header.hash(); { if self.processing.read().unwrap().contains(&h) { - return Err(x!(ImportError::AlreadyQueued)); + return Err(ImportError::AlreadyQueued.into()); } let mut bad = self.verification.bad.lock().unwrap(); if bad.contains(&h) { - return Err(x!(ImportError::KnownBad)); + return Err(ImportError::KnownBad.into()); } if bad.contains(&header.parent_hash) { bad.insert(h.clone()); - return Err(x!(ImportError::KnownBad)); + return Err(ImportError::KnownBad.into()); } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ab1c21af1..8fb0de9eb 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -655,10 +655,10 @@ impl BlockChainClient for Client where V: Verifier { { let header = BlockView::new(&bytes).header_view(); if self.chain.is_known(&header.sha3()) { - return Err(x!(ImportError::AlreadyInChain)); + return Err(ImportError::AlreadyInChain.into()); } if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown { - return Err(x!(BlockError::UnknownParent(header.parent_hash()))); + return Err(BlockError::UnknownParent(header.parent_hash()).into()); } } self.block_queue.import_block(bytes) diff --git a/ethcore/src/env_info.rs b/ethcore/src/env_info.rs index 18b8af856..e6d15cee6 100644 --- a/ethcore/src/env_info.rs +++ b/ethcore/src/env_info.rs @@ -47,10 +47,10 @@ impl Default for EnvInfo { number: 0, author: Address::new(), timestamp: 0, - difficulty: x!(0), - gas_limit: x!(0), + difficulty: 0.into(), + gas_limit: 0.into(), last_hashes: vec![], - gas_used: x!(0), + gas_used: 0.into(), } } } @@ -92,15 +92,15 @@ mod tests { assert_eq!(env_info.number, 1112339); assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()); - assert_eq!(env_info.gas_limit, x!(40000)); - assert_eq!(env_info.difficulty, x!(50000)); - assert_eq!(env_info.gas_used, x!(0)); + assert_eq!(env_info.gas_limit, 40000.into()); + assert_eq!(env_info.difficulty, 50000.into()); + assert_eq!(env_info.gas_used, 0.into()); } #[test] fn it_can_be_created_as_default() { let default_env_info = EnvInfo::default(); - assert_eq!(default_env_info.difficulty, x!(0)); + assert_eq!(default_env_info.difficulty, 0.into()); } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index cb06959d0..1dadb8a65 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -111,9 +111,9 @@ impl Engine for Ethash { let gas_limit = parent.gas_limit; let bound_divisor = self.ethash_params.gas_limit_bound_divisor; if gas_limit < gas_floor_target { - min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1)) + min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) } else { - max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor) + max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into() + (header.gas_used * 6.into() / 5.into()) / bound_divisor) } }; header.note_dirty(); @@ -255,12 +255,12 @@ impl Ethash { /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. pub fn boundary_to_difficulty(boundary: &H256) -> U256 { - U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice()))) + U256::from((U512::one() << 256) / U256::from(boundary.as_slice()).into()) } /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. pub fn difficulty_to_boundary(difficulty: &U256) -> H256 { - x!(U256::from((U512::one() << 256) / x!(difficulty))) + U256::from((U512::one() << 256) / difficulty.into()).into() } fn to_ethash(hash: H256) -> EH256 { @@ -308,7 +308,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -323,7 +323,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), x!(3141562), vec![]); + let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); @@ -346,24 +346,24 @@ mod tests { let engine = new_morden().engine; let schedule = engine.schedule(&EnvInfo { number: 10000000, - author: x!(0), + author: 0.into(), timestamp: 0, - difficulty: x!(0), + difficulty: 0.into(), last_hashes: vec![], - gas_used: x!(0), - gas_limit: x!(0) + gas_used: 0.into(), + gas_limit: 0.into() }); assert!(schedule.stack_limit > 0); let schedule = engine.schedule(&EnvInfo { number: 100, - author: x!(0), + author: 0.into(), timestamp: 0, - difficulty: x!(0), + difficulty: 0.into(), last_hashes: vec![], - gas_used: x!(0), - gas_limit: x!(0) + gas_used: 0.into(), + gas_limit: 0.into() }); assert!(!schedule.have_delegate_call); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 320a89cb8..291b4dba2 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -361,7 +361,7 @@ impl<'a> Executive<'a> { let refunds_bound = sstore_refunds + suicide_refunds; // real ammount to refund - let gas_left_prerefund = match result { Ok(x) => x, _ => x!(0) }; + let gas_left_prerefund = match result { Ok(x) => x, _ => 0.into() }; let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) / U256::from(2)); let gas_left = gas_left_prerefund + refunded; @@ -588,10 +588,10 @@ mod tests { let expected_trace = vec![ Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("cd1722f3947def4cf144679da39c4c32bdc35681"), - to: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), - value: x!(100), - gas: x!(100000), + from: "cd1722f3947def4cf144679da39c4c32bdc35681".into(), + to: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(), + value: 100.into(), + gas: 100000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -601,9 +601,9 @@ mod tests { subs: vec![Trace { depth: 1, action: trace::Action::Create(trace::Create { - from: x!("b010143a42d5980c7e5ef0e4a4416dc098a4fed3"), - value: x!(23), - gas: x!(67979), + from: "b010143a42d5980c7e5ef0e4a4416dc098a4fed3".into(), + value: 23.into(), + gas: 67979.into(), init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] }), result: trace::Res::Create(trace::CreateResult { @@ -642,7 +642,7 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(100_000); params.code = Some(code.clone()); - params.value = ActionValue::Transfer(x!(100)); + params.value = ActionValue::Transfer(100.into()); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(100)); @@ -660,7 +660,7 @@ mod tests { depth: 0, action: trace::Action::Create(trace::Create { from: params.sender, - value: x!(100), + value: 100.into(), gas: params.gas, init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], }), diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index c936ac207..99d2eed72 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -311,12 +311,12 @@ mod tests { fn get_test_env_info() -> EnvInfo { EnvInfo { number: 100, - author: x!(0), + author: 0.into(), timestamp: 0, - difficulty: x!(0), + difficulty: 0.into(), last_hashes: vec![], - gas_used: x!(0), - gas_limit: x!(0) + gas_used: 0.into(), + gas_limit: 0.into() } } diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 27ddc8a97..6f3949db3 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -114,11 +114,11 @@ mod test { #[test] fn existence() { - let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]}; + let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]}; assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&a)), None); assert_eq!(AccountDiff::diff_pod(None, Some(&a)), Some(AccountDiff{ - balance: Diff::Born(x!(69)), - nonce: Diff::Born(x!(0)), + balance: Diff::Born(69.into()), + nonce: Diff::Born(0.into()), code: Diff::Born(vec![]), storage: map![], })); @@ -126,11 +126,11 @@ mod test { #[test] fn basic() { - let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]}; - let b = PodAccount{balance: x!(42), nonce: x!(1), code: vec![], storage: map![]}; + let a = PodAccount{balance: 69.into(), nonce: 0.into(), code: vec![], storage: map![]}; + let b = PodAccount{balance: 42.into(), nonce: 1.into(), code: vec![], storage: map![]}; assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff { - balance: Diff::Changed(x!(69), x!(42)), - nonce: Diff::Changed(x!(0), x!(1)), + balance: Diff::Changed(69.into(), 42.into()), + nonce: Diff::Changed(0.into(), 1.into()), code: Diff::Same, storage: map![], })); @@ -138,11 +138,11 @@ mod test { #[test] fn code() { - let a = PodAccount{balance: x!(0), nonce: x!(0), code: vec![], storage: map![]}; - let b = PodAccount{balance: x!(0), nonce: x!(1), code: vec![0], storage: map![]}; + let a = PodAccount{balance: 0.into(), nonce: 0.into(), code: vec![], storage: map![]}; + let b = PodAccount{balance: 0.into(), nonce: 1.into(), code: vec![0], storage: map![]}; assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff { balance: Diff::Same, - nonce: Diff::Changed(x!(0), x!(1)), + nonce: Diff::Changed(0.into(), 1.into()), code: Diff::Changed(vec![], vec![0]), storage: map![], })); @@ -151,14 +151,14 @@ mod test { #[test] fn storage() { let a = PodAccount { - balance: x!(0), - nonce: x!(0), + balance: 0.into(), + nonce: 0.into(), code: vec![], storage: mapx![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0] }; let b = PodAccount { - balance: x!(0), - nonce: x!(0), + balance: 0.into(), + nonce: 0.into(), code: vec![], storage: mapx![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9] }; @@ -167,11 +167,11 @@ mod test { nonce: Diff::Same, code: Diff::Same, storage: map![ - x!(2) => Diff::new(x!(2), x!(3)), - x!(3) => Diff::new(x!(3), x!(0)), - x!(4) => Diff::new(x!(4), x!(0)), - x!(7) => Diff::new(x!(0), x!(7)), - x!(9) => Diff::new(x!(0), x!(9)) + 2.into() => Diff::new(2.into(), 3.into()), + 3.into() => Diff::new(3.into(), 0.into()), + 4.into() => Diff::new(4.into(), 0.into()), + 7.into() => Diff::new(0.into(), 7.into()), + 9.into() => Diff::new(0.into(), 9.into()), ], })); } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index eabca24a8..6e0e4f2f6 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -214,7 +214,7 @@ impl State { /// Initialise the code of account `a` so that it is `value` for `key`. /// NOTE: Account should have been created with `new_contract`. pub fn init_code(&mut self, a: &Address, code: Bytes) { - self.require_or_from(a, true, || Account::new_contract(x!(0), self.account_start_nonce), |_|{}).init_code(code); + self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).init_code(code); } /// Execute a given transaction. @@ -377,27 +377,27 @@ fn should_apply_create_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), action: Action::Create, - value: x!(100), + value: 100.into(), data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Create(trace::Create { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - value: x!(100), - gas: x!(77412), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 77412.into(), init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], }), result: trace::Res::Create(trace::CreateResult { @@ -438,27 +438,27 @@ fn should_trace_failed_create_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), action: Action::Create, - value: x!(100), + value: 100.into(), data: FromHex::from_hex("5b600056").unwrap(), }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Create(trace::Create { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - value: x!(100), - gas: x!(78792), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 78792.into(), init: vec![91, 96, 0, 86], }), result: trace::Res::FailedCreate, @@ -476,29 +476,29 @@ fn should_trace_call_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -519,28 +519,28 @@ fn should_trace_basic_call_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -561,15 +561,15 @@ fn should_trace_call_transaction_to_builtin() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = Spec::new_test().engine; let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0x1)), - value: x!(0), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0x1.into()), + value: 0.into(), data: vec![], }.sign(&"".sha3()); @@ -579,10 +579,10 @@ fn should_trace_call_transaction_to_builtin() { assert_eq!(result.trace, Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!("0000000000000000000000000000000000000001"), - value: x!(0), - gas: x!(79_000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: "0000000000000000000000000000000000000001".into(), + value: 0.into(), + gas: 79_000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -601,29 +601,29 @@ fn should_not_trace_subcall_transaction_to_builtin() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = Spec::new_test().engine; let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(0), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); let vm_factory = Default::default(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(0), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -643,30 +643,30 @@ fn should_not_trace_callcode() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = Spec::new_test().engine; let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(0), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); let vm_factory = Default::default(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(0), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -686,33 +686,33 @@ fn should_not_trace_delegatecall() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); info.number = 0x789b0; let engine = Spec::new_test().engine; println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(0), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); + state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); let vm_factory = Default::default(); let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(0), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -732,29 +732,29 @@ fn should_trace_failed_call_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::FailedCall, @@ -774,30 +774,30 @@ fn should_trace_call_with_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -807,10 +807,10 @@ fn should_trace_call_with_subcall_transaction() { subs: vec![Trace { depth: 1, action: trace::Action::Call(trace::Call { - from: x!(0xa), - to: x!(0xb), - value: x!(0), - gas: x!(78934), + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -832,29 +832,29 @@ fn should_trace_call_with_basic_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -864,10 +864,10 @@ fn should_trace_call_with_basic_subcall_transaction() { subs: vec![Trace { depth: 1, action: trace::Action::Call(trace::Call { - from: x!(0xa), - to: x!(0xb), - value: x!(69), - gas: x!(2300), + from: 0xa.into(), + to: 0xb.into(), + value: 69.into(), + gas: 2300.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult::default()), @@ -886,29 +886,29 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -929,30 +929,30 @@ fn should_trace_failed_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![],//600480600b6000396000f35b600056 }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -962,10 +962,10 @@ fn should_trace_failed_subcall_transaction() { subs: vec![Trace { depth: 1, action: trace::Action::Call(trace::Call { - from: x!(0xa), - to: x!(0xb), - value: x!(0), - gas: x!(78934), + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), input: vec![], }), result: trace::Res::FailedCall, @@ -984,31 +984,31 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![], }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); - state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -1018,10 +1018,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { subs: vec![Trace { depth: 1, action: trace::Action::Call(trace::Call { - from: x!(0xa), - to: x!(0xb), - value: x!(0), - gas: x!(78934), + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -1031,10 +1031,10 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { subs: vec![Trace { depth: 2, action: trace::Action::Call(trace::Call { - from: x!(0xb), - to: x!(0xc), - value: x!(0), - gas: x!(78868), + from: 0xb.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78868.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -1057,31 +1057,31 @@ fn should_trace_failed_subcall_with_subcall_transaction() { let mut state = get_temp_state_in(temp.as_path()); let mut info = EnvInfo::default(); - info.gas_limit = x!(1_000_000); + info.gas_limit = 1_000_000.into(); let engine = TestEngine::new(5); let t = Transaction { - nonce: x!(0), - gas_price: x!(0), - gas: x!(100_000), - action: Action::Call(x!(0xa)), - value: x!(100), + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), data: vec![],//600480600b6000396000f35b600056 }.sign(&"".sha3()); - state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&x!(0xb), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); - state.init_code(&x!(0xc), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &x!(100)); + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &100.into()); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { depth: 0, action: trace::Action::Call(trace::Call { - from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"), - to: x!(0xa), - value: x!(100), - gas: x!(79000), + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -1091,21 +1091,21 @@ fn should_trace_failed_subcall_with_subcall_transaction() { subs: vec![Trace { depth: 1, action: trace::Action::Call(trace::Call { - from: x!(0xa), - to: x!(0xb), - value: x!(0), - gas: x!(78934), + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), input: vec![], }), result: trace::Res::FailedCall, subs: vec![Trace { depth: 2, action: trace::Action::Call(trace::Call { - from: x!(0xb), - to: x!(0xc), - value: x!(0), - gas: x!(78868), - input: vec![], + from: 0xb.into(), + to: 0xc.into(), + value: 0.into(), + gas: 78868.into(), + input: vec![], }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3), @@ -1125,7 +1125,7 @@ fn code_from_database() { let temp = RandomTempPath::new(); let (root, db) = { let mut state = get_temp_state_in(temp.as_path()); - state.require_or_from(&a, false, ||Account::new_contract(x!(42), x!(0)), |_|{}); + state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); state.init_code(&a, vec![1, 2, 3]); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); state.commit(); diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 65b314663..247bbb398 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -74,7 +74,7 @@ mod tests { topics: vec![], data: vec![] }); - sub_state.sstore_clears_count = x!(5); + sub_state.sstore_clears_count = 5.into(); sub_state.suicides.insert(address_from_u64(10u64)); let mut sub_state_2 = Substate::new(); @@ -84,11 +84,11 @@ mod tests { topics: vec![], data: vec![] }); - sub_state_2.sstore_clears_count = x!(7); + sub_state_2.sstore_clears_count = 7.into(); sub_state.accrue(sub_state_2); assert_eq!(sub_state.contracts_created.len(), 2); - assert_eq!(sub_state.sstore_clears_count, x!(12)); + assert_eq!(sub_state.sstore_clears_count, 12.into()); assert_eq!(sub_state.suicides.len(), 1); } } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d734b0b47..4a71bf7d7 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -136,7 +136,7 @@ fn can_mine() { let client_result = get_test_client_with_blocks(vec![dummy_blocks[0].clone()]); let client = client_result.reference(); - let b = client.prepare_sealing(Address::default(), x!(31415926), vec![], vec![]).0.unwrap(); + let b = client.prepare_sealing(Address::default(), 31415926.into(), vec![], vec![]).0.unwrap(); assert_eq!(*b.block().header().parent_hash(), BlockView::new(&dummy_blocks[0]).header_view().sha3()); assert!(client.try_seal(b.lock(), vec![]).is_ok()); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 7262da9e8..6a370e49f 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -98,8 +98,8 @@ pub fn create_test_block(header: &Header) -> Bytes { fn create_unverifiable_block_header(order: u32, parent_hash: H256) -> Header { let mut header = Header::new(); - header.gas_limit = x!(0); - header.difficulty = x!(order * 100); + header.gas_limit = 0.into(); + header.difficulty = order * 100.into(); header.timestamp = (order * 10) as u64; header.number = order as u64; header.parent_hash = parent_hash; @@ -335,7 +335,7 @@ pub fn get_bad_state_dummy_block() -> Bytes { block_header.timestamp = 40; block_header.number = 1; block_header.parent_hash = test_spec.genesis_header().hash(); - block_header.state_root = x!(0xbad); + block_header.state_root = 0xbad.into(); create_test_block(&block_header) } diff --git a/ethcore/src/types/receipt.rs b/ethcore/src/types/receipt.rs index f07a12212..78216eb16 100644 --- a/ethcore/src/types/receipt.rs +++ b/ethcore/src/types/receipt.rs @@ -105,10 +105,10 @@ pub struct LocalizedReceipt { fn test_basic() { let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); let r = Receipt::new( - x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), - x!(0x40cae), + "2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(), + 0x40cae.into(), vec![LogEntry { - address: x!("dcf421d093428b096ca501a7cd1a740855a7976f"), + address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(), topics: vec![], data: vec![0u8; 32] }] From 3abaeadcf3794708246042d961096ef349d65519 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 17:18:21 +0200 Subject: [PATCH 54/88] finish purging x! from ethcore --- ethcore/src/state_diff.rs | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/ethcore/src/state_diff.rs b/ethcore/src/state_diff.rs index 6c41d167c..1c1975e70 100644 --- a/ethcore/src/state_diff.rs +++ b/ethcore/src/state_diff.rs @@ -59,19 +59,19 @@ mod test { #[test] fn create_delete() { - let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); + let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); assert_eq!(StateDiff::diff_pod(&a, &PodState::new()), StateDiff(map![ - x!(1) => AccountDiff{ - balance: Diff::Died(x!(69)), - nonce: Diff::Died(x!(0)), + 1.into() => AccountDiff{ + balance: Diff::Died(69.into()), + nonce: Diff::Died(0.into()), code: Diff::Died(vec![]), storage: map![], } ])); assert_eq!(StateDiff::diff_pod(&PodState::new(), &a), StateDiff(map![ - x!(1) => AccountDiff{ - balance: Diff::Born(x!(69)), - nonce: Diff::Born(x!(0)), + 1.into() => AccountDiff{ + balance: Diff::Born(69.into()), + nonce: Diff::Born(0.into()), code: Diff::Born(vec![]), storage: map![], } @@ -80,23 +80,23 @@ mod test { #[test] fn create_delete_with_unchanged() { - let a = PodState::from(map![ x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]) ]); + let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); let b = PodState::from(map![ - x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), - x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) + 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]), + 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) ]); assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![ - x!(2) => AccountDiff{ - balance: Diff::Born(x!(69)), - nonce: Diff::Born(x!(0)), + 2.into() => AccountDiff{ + balance: Diff::Born(69.into()), + nonce: Diff::Born(0.into()), code: Diff::Born(vec![]), storage: map![], } ])); assert_eq!(StateDiff::diff_pod(&b, &a), StateDiff(map![ - x!(2) => AccountDiff{ - balance: Diff::Died(x!(69)), - nonce: Diff::Died(x!(0)), + 2.into() => AccountDiff{ + balance: Diff::Died(69.into()), + nonce: Diff::Died(0.into()), code: Diff::Died(vec![]), storage: map![], } @@ -106,17 +106,17 @@ mod test { #[test] fn change_with_unchanged() { let a = PodState::from(map![ - x!(1) => PodAccount::new(x!(69), x!(0), vec![], map![]), - x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) + 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]), + 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) ]); let b = PodState::from(map![ - x!(1) => PodAccount::new(x!(69), x!(1), vec![], map![]), - x!(2) => PodAccount::new(x!(69), x!(0), vec![], map![]) + 1.into() => PodAccount::new(69.into(), 1.into(),, vec![], map![]), + 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) ]); assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![ - x!(1) => AccountDiff{ + 1.into() => AccountDiff{ balance: Diff::Same, - nonce: Diff::Changed(x!(0), x!(1)), + nonce: Diff::Changed(0.into(), 1.into()), code: Diff::Same, storage: map![], } From c62bfcddef1fedaaa76eed2870071cd93846c1c7 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 17:25:25 +0200 Subject: [PATCH 55/88] finish purging x! from parity, remove x! and xx! macros --- miner/src/lib.rs | 4 ++-- miner/src/miner.rs | 6 +++--- sync/src/chain.rs | 6 +++--- util/src/common.rs | 14 -------------- util/src/keys/store.rs | 2 +- 5 files changed, 9 insertions(+), 23 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index a1780efff..f91811948 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -150,10 +150,10 @@ pub trait MinerService : Send + Sync { fn last_nonce(&self, address: &Address) -> Option; /// Suggested gas price. - fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) } + fn sensible_gas_price(&self) -> U256 { 20000000000u64.into() } /// Suggested gas limit. - fn sensible_gas_limit(&self) -> U256 { x!(21000) } + fn sensible_gas_limit(&self) -> U256 { 21000.into() } /// Latest account balance in pending state. fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index fc63aec6c..d9abb09f4 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -137,7 +137,7 @@ impl Miner { Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { trace!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); // Exit early if gas left is smaller then min_tx_gas - let min_tx_gas: U256 = x!(21000); // TODO: figure this out properly. + let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly. if gas_limit - gas_used < min_tx_gas { break; } @@ -337,11 +337,11 @@ impl MinerService for Miner { fn sensible_gas_price(&self) -> U256 { // 10% above our minimum. - *self.transaction_queue.lock().unwrap().minimal_gas_price() * x!(110) / x!(100) + *self.transaction_queue.lock().unwrap().minimal_gas_price() * 110.into() / 100.into() } fn sensible_gas_limit(&self) -> U256 { - *self.gas_floor_target.read().unwrap() / x!(5) + *self.gas_floor_target.read().unwrap() / 5.into() } fn transactions_limit(&self) -> usize { diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 2f31f1d47..dcfdc1c16 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1310,8 +1310,8 @@ mod tests { fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); - header.gas_limit = x!(0); - header.difficulty = x!(order * 100); + header.gas_limit = 0.into(); + header.difficulty = (order * 100).into(); header.timestamp = (order * 10) as u64; header.number = order as u64; header.parent_hash = parent_hash; @@ -1327,7 +1327,7 @@ mod tests { fn get_dummy_blocks(order: u32, parent_hash: H256) -> Bytes { let mut rlp = RlpStream::new_list(1); rlp.append_raw(&get_dummy_block(order, parent_hash), 1); - let difficulty: U256 = x!(100 * order); + let difficulty: U256 = (100 * order).into(); rlp.append(&difficulty); rlp.out() } diff --git a/util/src/common.rs b/util/src/common.rs index 7ed660f29..c1de582df 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -68,20 +68,6 @@ macro_rules! mapx { }} } -#[macro_export] -macro_rules! x { - ( $x:expr ) => { - From::from($x) - } -} - -#[macro_export] -macro_rules! xx { - ( $x:expr ) => { - From::from(From::from($x)) - } -} - #[macro_export] macro_rules! flush { ($($arg:tt)*) => ($crate::flush(format!("{}", format_args!($($arg)*)))); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 296f7ad37..3402596d3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -627,7 +627,7 @@ mod tests { sstore.sign(&address, &H256::random()).unwrap() }; - assert!(signature != x!(0)); + assert!(signature != 0.into()); } #[test] From da9d6bf8d5a8824d4ea712403adace4bce5b256b Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 17:29:01 +0200 Subject: [PATCH 56/88] rename [hash_]mapx to [hash_]map_into --- ethcore/src/pod_account.rs | 4 ++-- util/src/common.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 6f3949db3..96642d1f8 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -154,13 +154,13 @@ mod test { balance: 0.into(), nonce: 0.into(), code: vec![], - storage: mapx![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0] + storage: map_into![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0] }; let b = PodAccount { balance: 0.into(), nonce: 0.into(), code: vec![], - storage: mapx![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9] + storage: map_into![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9] }; assert_eq!(AccountDiff::diff_pod(Some(&a), Some(&b)), Some(AccountDiff { balance: Diff::Same, diff --git a/util/src/common.rs b/util/src/common.rs index c1de582df..2eb2ea017 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -36,7 +36,7 @@ macro_rules! hash_map { } #[macro_export] -macro_rules! hash_mapx { +macro_rules! hash_map_into { ( $( $x:expr => $y:expr ),* ) => {{ let mut x = HashMap::new(); $( @@ -58,7 +58,7 @@ macro_rules! map { } #[macro_export] -macro_rules! mapx { +macro_rules! map_into { ( $( $x:expr => $y:expr ),* ) => {{ let mut x = BTreeMap::new(); $( From 4f732972bc366b758ef97190380d86192cef779c Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 19:01:37 +0200 Subject: [PATCH 57/88] refactoring to hold miner within the client --- ethcore/Cargo.toml | 1 + ethcore/src/client/client.rs | 32 ++++++++++++++++++++++++-------- ethcore/src/client/mod.rs | 11 +++++++++-- sync/src/chain.rs | 22 ++-------------------- sync/src/io.rs | 8 ++++---- sync/src/lib.rs | 11 ----------- sync/src/tests/chain.rs | 2 +- sync/src/tests/helpers.rs | 2 +- 8 files changed, 42 insertions(+), 47 deletions(-) diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 34a010794..f63eb957c 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -29,6 +29,7 @@ ethcore-devtools = { path = "../devtools" } ethjson = { path = "../json" } bloomchain = "0.1" "ethcore-ipc" = { path = "../ipc/rpc" } +ethminer = { path = "../miner" } [features] jit = ["evmjit"] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8f6d607ba..7a616fdbc 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -90,6 +90,7 @@ pub struct Client where V: Verifier { panic_handler: Arc, verifier: PhantomData, vm_factory: Arc, + miner: Arc, } const HISTORY: u64 = 1200; @@ -126,7 +127,13 @@ pub fn append_path(path: &Path, item: &str) -> String { impl Client where V: Verifier { /// Create a new client with given spec and DB path and custom verifier. - pub fn new_with_verifier(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result>, ClientError> { + pub fn new_with_verifier( + config: ClientConfig, + spec: Spec, + path: &Path, + message_channel: IoChannel) + -> Result>, ClientError> + { let path = get_db_path(path, config.pruning, spec.genesis_header().hash()); let gb = spec.genesis_block(); let chain = Arc::new(BlockChain::new(config.blockchain, &gb, &path)); @@ -328,18 +335,13 @@ impl Client where V: Verifier { { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); - io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { - imported: imported_blocks, - invalid: invalid_blocks, - enacted: enacted, - retracted: retracted, - })).unwrap(); + self.miner.chain_new_blocks(imported_blocks, invalid_blocks, enacted, retracted); } } { if self.chain_info().best_block_hash != original_best { - io.send(NetworkIoMessage::User(SyncMessage::NewChainHead)).unwrap(); + self.miner.update_sealing(&self); } } @@ -778,6 +780,20 @@ impl ExtendedBlockChainClient for Client where V: Verifier { } } +impl MiningClient for Client { + fn import_transactions(&self, transactions: Vec) -> Vec> { + let fetch_account = |a: &Address| AccountDetails { + nonce: self.latest_nonce(a), + balance: self.latest_balance(a), + }; + self.miner.import_transactions(transactions, fetch_account) + } + + fn all_transactions(&self) -> Vec { + self.miner.all_transactions() + } +} + impl MayPanic for Client { fn on_panic(&self, closure: F) where F: OnPanicListener { self.panic_handler.on_panic(closure); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 5537f8e66..dfef54a40 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -178,12 +178,19 @@ pub trait BlockChainClient : Sync + Send { /// Extended client interface used for mining pub trait ExtendedBlockChainClient : BlockChainClient { - // TODO [todr] Should be moved to miner crate eventually. /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; - // TODO [todr] Should be moved to miner crate eventually. /// Returns ClosedBlock prepared for sealing. fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> (Option, HashSet); } + +/// Extended client interface that supports mining +pub trait MiningClient : BlockChainClient { + /// import transactions from network/other 3rd party + fn import_transactions(&self, transactions: Vec) -> Vec>; + + /// list all transactions + fn all_transactions(&self) -> Vec; +} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 2f31f1d47..a0d0ba1fa 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -903,7 +903,7 @@ impl ChainSync { nonce: chain.latest_nonce(a), balance: chain.latest_balance(a), }; - let _ = self.miner.import_transactions(transactions, fetch_account); + let _ = io.chain().import_transactions(transactions, fetch_account); Ok(()) } @@ -1226,7 +1226,7 @@ impl ChainSync { return 0; } - let mut transactions = self.miner.all_transactions(); + let mut transactions = io.chain().all_transactions(); if transactions.is_empty() { return 0; } @@ -1275,24 +1275,6 @@ impl ChainSync { pub fn maintain_sync(&mut self, io: &mut SyncIo) { self.check_resume(io); } - - /// called when block is imported to chain, updates transactions queue and propagates the blocks - pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - if io.is_chain_queue_empty() { - // Notify miner - self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted); - // Propagate latests blocks - self.propagate_latest_blocks(io); - } - if !invalid.is_empty() { - trace!(target: "sync", "Bad blocks in the queue, restarting"); - self.restart_on_bad_block(io); - } - } - - pub fn chain_new_head(&mut self, io: &mut SyncIo) { - self.miner.update_sealing(io.chain()); - } } #[cfg(test)] diff --git a/sync/src/io.rs b/sync/src/io.rs index 84697a021..49cccd7ca 100644 --- a/sync/src/io.rs +++ b/sync/src/io.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethcore::client::BlockChainClient; +use ethcore::client::MiningClient; use util::{NetworkContext, PeerId, PacketId,}; use util::error::UtilError; use ethcore::service::SyncMessage; @@ -32,7 +32,7 @@ pub trait SyncIo { /// Send a packet to a peer. fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError>; /// Get the blockchain - fn chain(&self) -> &BlockChainClient; + fn chain(&self) -> &MiningClient; /// Returns peer client identifier string fn peer_info(&self, peer_id: PeerId) -> String { peer_id.to_string() @@ -46,12 +46,12 @@ pub trait SyncIo { /// Wraps `NetworkContext` and the blockchain client pub struct NetSyncIo<'s, 'h> where 'h: 's { network: &'s NetworkContext<'h, SyncMessage>, - chain: &'s BlockChainClient + chain: &'s MiningClient } impl<'s, 'h> NetSyncIo<'s, 'h> { /// Creates a new instance from the `NetworkContext` and the blockchain client reference. - pub fn new(network: &'s NetworkContext<'h, SyncMessage>, chain: &'s BlockChainClient) -> NetSyncIo<'s, 'h> { + pub fn new(network: &'s NetworkContext<'h, SyncMessage>, chain: &'s MiningClient) -> NetSyncIo<'s, 'h> { NetSyncIo { network: network, chain: chain, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index c8dc93db6..6b72a24fc 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -166,16 +166,5 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { - match *message { - SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { - let mut sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); - }, - SyncMessage::NewChainHead => { - let mut sync_io = NetSyncIo::new(io, self.chain.deref()); - self.sync.write().unwrap().chain_new_head(&mut sync_io); - }, - _ => {/* Ignore other messages */}, - } } } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 09e83e358..463771ffe 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockID, EachBlockWith}; +use ethcore::client::{MiningClient, BlockID, EachBlockWith}; use chain::{SyncState}; use super::helpers::*; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index d1ffde0f0..70ddb78db 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -63,7 +63,7 @@ impl<'p> SyncIo for TestIo<'p> { Ok(()) } - fn chain(&self) -> &BlockChainClient { + fn chain(&self) -> &MiningClient { self.chain } } From 4ccaabde40365d0815a9fcd0c69eecc041cea784 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 19:30:40 +0200 Subject: [PATCH 58/88] add transaction count verifier tests --- rpc/src/v1/tests/eth.rs | 96 ++++++++++++++++++++++++++++++++++++----- rpc/src/v1/tests/mod.rs | 25 ++++++++--- 2 files changed, 104 insertions(+), 17 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 9b2cb3195..0c159ceb2 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,15 +19,18 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; +use ethcore::ids::BlockID; use ethcore::client::{Client, BlockChainClient, ClientConfig}; use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; +use ethcore::views::BlockView; use ethcore::ethereum; use ethminer::{Miner, MinerService, ExternalMiner}; use devtools::RandomTempPath; +use util::Hashable; use util::io::IoChannel; -use util::hash::Address; -use util::numbers::{Uint, U256}; +use util::hash::{Address, H256}; +use util::numbers::U256; use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; use ethjson::blockchain::BlockChain; @@ -72,8 +75,8 @@ struct EthTester { } impl EthTester { - fn from_chain(chain: BlockChain) -> Self { - let tester = Self::from_spec_provider(|| make_spec(&chain)); + fn from_chain(chain: &BlockChain) -> Self { + let tester = Self::from_spec_provider(|| make_spec(chain)); for b in &chain.blocks_rlp() { if Block::is_good(&b) { @@ -83,7 +86,9 @@ impl EthTester { } } - assert!(tester.client.chain_info().best_block_hash == chain.best_block.into()); + tester.client.flush_queue(); + + assert!(tester.client.chain_info().best_block_hash == chain.best_block.clone().into()); tester } @@ -116,13 +121,13 @@ impl EthTester { #[test] fn harness_works() { let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); - let _ = EthTester::from_chain(chain); + let _ = EthTester::from_chain(&chain); } #[test] fn eth_get_balance() { let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); - let tester = EthTester::from_chain(chain); + let tester = EthTester::from_chain(&chain); // final account state let req_latest = r#"{ "jsonrpc": "2.0", @@ -148,7 +153,7 @@ fn eth_get_balance() { #[test] fn eth_block_number() { let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); - let tester = EthTester::from_chain(chain); + let tester = EthTester::from_chain(&chain); let req_number = r#"{ "jsonrpc": "2.0", "method": "eth_blockNumber", @@ -206,7 +211,6 @@ const TRANSACTION_COUNT_SPEC: &'static [u8] = br#"{ } "#; -#[cfg(test)] #[test] fn eth_transaction_count() { use util::crypto::Secret; @@ -271,4 +275,76 @@ fn eth_transaction_count() { let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#; assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending); -} \ No newline at end of file +} + +fn verify_transaction_counts(name: String, chain: BlockChain) { + struct PanicHandler(String); + impl Drop for PanicHandler { + fn drop(&mut self) { + if ::std::thread::panicking() { + println!("Test failed: {}", self.0); + } + } + } + + let _panic = PanicHandler(name); + + fn by_hash(hash: H256, count: usize, id: &mut usize) -> (String, String) { + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": [ + ""#.to_owned() + format!("0x{:?}", hash).as_ref() + r#"" + ], + "id": "# + format!("{}", *id).as_ref() + r#" + }"#; + + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + + format!("0x{:02x}", count).as_ref() + + r#"","id":"# + + format!("{}", *id).as_ref() + r#"}"#; + *id += 1; + (req, res) + } + + fn by_number(num: u64, count: usize, id: &mut usize) -> (String, String) { + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": [ + "#.to_owned() + &::serde_json::to_string(&U256::from(num)).unwrap() + r#" + ], + "id": "# + format!("{}", *id).as_ref() + r#" + }"#; + + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + + format!("0x{:02x}", count).as_ref() + + r#"","id":"# + + format!("{}", *id).as_ref() + r#"}"#; + *id += 1; + (req, res) + } + + let tester = EthTester::from_chain(&chain); + + let mut id = 1; + for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| BlockView::new(b)) { + let count = b.transactions_count(); + + let hash = b.sha3(); + let number = b.header_view().number(); + + let (req, res) = by_hash(hash, count, &mut id); + assert_eq!(tester.handler.handle_request(&req), Some(res)); + + // uncles can share block numbers, so skip them. + if tester.client.block_hash(BlockID::Number(number)) == Some(hash) { + let (req, res) = by_number(number, count, &mut id); + assert_eq!(tester.handler.handle_request(&req), Some(res)); + } + } +} + +register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest"); +register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest"); +register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest"); \ No newline at end of file diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 3455bfd1f..9e71addd4 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -13,11 +13,15 @@ pub mod helpers; // extract the chain with that name. This will panic if no chain by that name // is found. macro_rules! extract_chain { - ($file:expr, $name:expr) => {{ + (iter $file:expr) => {{ const RAW_DATA: &'static [u8] = include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); + ::ethjson::blockchain::Test::load(RAW_DATA).unwrap().into_iter() + }}; + + ($file:expr, $name:expr) => {{ let mut chain = None; - for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { + for (name, c) in extract_chain!(iter $file) { if name == $name { chain = Some(c); break; @@ -27,14 +31,21 @@ macro_rules! extract_chain { }}; ($file:expr) => {{ - const RAW_DATA: &'static [u8] = - include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); - - ::ethjson::blockchain::Test::load(RAW_DATA) - .unwrap().into_iter().next().unwrap().1 + extract_chain!(iter $file).next().unwrap().1 }}; } +macro_rules! register_test { + ($name:ident, $cb:expr, $file:expr) => { + #[test] + fn $name() { + for (name, chain) in extract_chain!(iter $file) { + $cb(name, chain); + } + } + } +} + #[cfg(test)] mod mocked; #[cfg(test)] From c81e4e24b303a765120fefe15600705918aa9afe Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 19:51:24 +0200 Subject: [PATCH 59/88] add ability to have heavy tests --- rpc/src/v1/tests/mod.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 9e71addd4..a48727475 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -43,7 +43,27 @@ macro_rules! register_test { $cb(name, chain); } } - } + }; + + (heavy $name:ident, $cb:expr, $file:expr) => { + #[test] + #[cfg(feature = "test-heavy")] + fn $name() { + for (name, chain) in extract_chain!(iter $file) { + $cb(name, chain); + } + } + }; + + (ignore $name:ident, $cb:expr, $file:expr) => { + #[test] + #[ignore] + fn $name() { + for (name, chain) in extract_chain!(iter $file) { + $cb(name, chain); + } + } + }; } #[cfg(test)] From 8e252d5f1ba81585292477be869f3e1843c16fa1 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 19:52:53 +0200 Subject: [PATCH 60/88] refactored to merge client & client --- ethcore/Cargo.toml | 2 +- ethcore/src/client/client.rs | 41 +++++++++---------- ethcore/src/client/mod.rs | 17 ++++---- ethcore/src/client/test_client.rs | 11 +++++ ethcore/src/lib.rs | 2 + {miner/src => ethcore/src/miner}/external.rs | 0 {miner/src => ethcore/src/miner}/miner.rs | 20 ++++----- miner/src/lib.rs => ethcore/src/miner/mod.rs | 32 +++++---------- .../src/miner}/transaction_queue.rs | 4 +- ethcore/src/service.rs | 5 ++- 10 files changed, 68 insertions(+), 66 deletions(-) rename {miner/src => ethcore/src/miner}/external.rs (100%) rename {miner/src => ethcore/src/miner}/miner.rs (98%) rename miner/src/lib.rs => ethcore/src/miner/mod.rs (89%) rename {miner/src => ethcore/src/miner}/transaction_queue.rs (99%) diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index f63eb957c..1de24ee32 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -29,7 +29,7 @@ ethcore-devtools = { path = "../devtools" } ethjson = { path = "../json" } bloomchain = "0.1" "ethcore-ipc" = { path = "../ipc/rpc" } -ethminer = { path = "../miner" } +rayon = "0.3.1" [features] jit = ["evmjit"] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 7a616fdbc..d23bffa31 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -48,6 +48,7 @@ use trace; pub use types::blockchain_info::BlockChainInfo; pub use types::block_status::BlockStatus; use evm::Factory as EvmFactory; +use miner::{Miner, MinerService, TransactionImportResult, AccountDetails}; impl fmt::Display for BlockChainInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -90,7 +91,7 @@ pub struct Client where V: Verifier { panic_handler: Arc, verifier: PhantomData, vm_factory: Arc, - miner: Arc, + miner: Arc, } const HISTORY: u64 = 1200; @@ -103,8 +104,8 @@ const CLIENT_DB_VER_STR: &'static str = "5.3"; impl Client { /// Create a new client with given spec and DB path. - pub fn new(config: ClientConfig, spec: Spec, path: &Path, message_channel: IoChannel ) -> Result, ClientError> { - Client::::new_with_verifier(config, spec, path, message_channel) + pub fn new(config: ClientConfig, spec: Spec, path: &Path, miner: Arc, message_channel: IoChannel ) -> Result, ClientError> { + Client::::new_with_verifier(config, spec, path, miner, message_channel) } } @@ -131,6 +132,7 @@ impl Client where V: Verifier { config: ClientConfig, spec: Spec, path: &Path, + miner: Arc, message_channel: IoChannel) -> Result>, ClientError> { @@ -162,6 +164,7 @@ impl Client where V: Verifier { panic_handler: panic_handler, verifier: PhantomData, vm_factory: Arc::new(EvmFactory::new(config.vm_type)), + miner: miner, }; Ok(Arc::new(client)) @@ -335,13 +338,13 @@ impl Client where V: Verifier { { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); - self.miner.chain_new_blocks(imported_blocks, invalid_blocks, enacted, retracted); + self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted); } } { if self.chain_info().best_block_hash != original_best { - self.miner.update_sealing(&self); + self.miner.update_sealing(self); } } @@ -705,10 +708,21 @@ impl BlockChainClient for Client where V: Verifier { fn last_hashes(&self) -> LastHashes { self.build_last_hashes(self.chain.best_block_hash()) } + + fn import_transactions(&self, transactions: Vec) -> Vec> { + let fetch_account = |a: &Address| AccountDetails { + nonce: self.latest_nonce(a), + balance: self.latest_balance(a), + }; + self.miner.import_transactions(transactions, fetch_account) + } + + fn all_transactions(&self) -> Vec { + self.miner.all_transactions() + } } impl ExtendedBlockChainClient for Client where V: Verifier { - // TODO [todr] Should be moved to miner crate eventually. fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> (Option, HashSet) { let engine = self.engine.deref().deref(); @@ -774,26 +788,11 @@ impl ExtendedBlockChainClient for Client where V: Verifier { (Some(b), invalid_transactions) } - // TODO [todr] Should be moved to miner crate eventually. fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result { block.try_seal(self.engine.deref().deref(), seal) } } -impl MiningClient for Client { - fn import_transactions(&self, transactions: Vec) -> Vec> { - let fetch_account = |a: &Address| AccountDetails { - nonce: self.latest_nonce(a), - balance: self.latest_balance(a), - }; - self.miner.import_transactions(transactions, fetch_account) - } - - fn all_transactions(&self) -> Vec { - self.miner.all_transactions() - } -} - impl MayPanic for Client { fn on_panic(&self, closure: F) where F: OnPanicListener { self.panic_handler.on_panic(closure); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index dfef54a40..67c753d46 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -46,6 +46,8 @@ use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use trace::LocalizedTrace; use evm::Factory as EvmFactory; +use miner::{TransactionImportResult, AccountDetails}; +use error::Error as EthError; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -174,6 +176,12 @@ pub trait BlockChainClient : Sync + Send { /// Get last hashes starting from best block. fn last_hashes(&self) -> LastHashes; + + /// import transactions from network/other 3rd party + fn import_transactions(&self, transactions: Vec) -> Vec>; + + /// list all transactions + fn all_transactions(&self) -> Vec; } /// Extended client interface used for mining @@ -185,12 +193,3 @@ pub trait ExtendedBlockChainClient : BlockChainClient { fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> (Option, HashSet); } - -/// Extended client interface that supports mining -pub trait MiningClient : BlockChainClient { - /// import transactions from network/other 3rd party - fn import_transactions(&self, transactions: Vec) -> Vec>; - - /// list all transactions - fn all_transactions(&self) -> Vec; -} diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 5c093b720..ad398bbcb 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -35,6 +35,9 @@ use executive::Executed; use error::{ExecutionError}; use trace::LocalizedTrace; +use miner::{TransactionImportResult, AccountDetails}; +use error::Error as EthError; + /// Test client. pub struct TestBlockChainClient { /// Blocks. @@ -479,4 +482,12 @@ impl BlockChainClient for TestBlockChainClient { fn block_traces(&self, _trace: BlockID) -> Option> { unimplemented!(); } + + fn import_transactions(&self, transactions: Vec) -> Vec> { + unimplemented!(); + } + + fn all_transactions(&self) -> Vec { + unimplemented!(); + } } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 1d4ddadbc..5cf9d50a1 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -90,6 +90,7 @@ extern crate crossbeam; extern crate ethjson; extern crate bloomchain; #[macro_use] extern crate ethcore_ipc as ipc; +extern crate rayon; #[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; @@ -109,6 +110,7 @@ pub mod views; pub mod pod_state; pub mod engine; pub mod migrations; +pub mod miner; mod blooms; mod db; diff --git a/miner/src/external.rs b/ethcore/src/miner/external.rs similarity index 100% rename from miner/src/external.rs rename to ethcore/src/miner/external.rs diff --git a/miner/src/miner.rs b/ethcore/src/miner/miner.rs similarity index 98% rename from miner/src/miner.rs rename to ethcore/src/miner/miner.rs index 7438e7e9b..c4bec7659 100644 --- a/miner/src/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -19,16 +19,16 @@ use std::sync::atomic::AtomicBool; use util::*; use util::keys::store::{AccountService, AccountProvider}; -use ethcore::views::{BlockView, HeaderView}; -use ethcore::client::{ExtendedBlockChainClient, BlockID}; -use ethcore::block::{ClosedBlock, IsBlock}; -use ethcore::error::*; -use ethcore::client::{Executive, Executed, EnvInfo, TransactOptions}; -use ethcore::transaction::SignedTransaction; -use ethcore::receipt::{Receipt}; -use ethcore::spec::Spec; -use ethcore::engine::Engine; -use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; +use views::{BlockView, HeaderView}; +use client::{ExtendedBlockChainClient, BlockID}; +use block::{ClosedBlock, IsBlock}; +use error::*; +use client::{Executive, Executed, EnvInfo, TransactOptions}; +use transaction::SignedTransaction; +use receipt::{Receipt}; +use spec::Spec; +use engine::Engine; +use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; /// Keeps track of transactions using priority queue and holds currently mined block. pub struct Miner { diff --git a/miner/src/lib.rs b/ethcore/src/miner/mod.rs similarity index 89% rename from miner/src/lib.rs rename to ethcore/src/miner/mod.rs index db3315376..95453027c 100644 --- a/miner/src/lib.rs +++ b/ethcore/src/miner/mod.rs @@ -26,12 +26,11 @@ //! ```rust //! extern crate ethcore_util as util; //! extern crate ethcore; -//! extern crate ethminer; //! use std::env; //! use util::network::{NetworkService, NetworkConfiguration}; -//! use ethcore::client::{Client, ClientConfig}; -//! use ethcore::ethereum; -//! use ethminer::{Miner, MinerService}; +//! use client::{Client, ClientConfig}; +//! use ethereum; +//! use ethcore::miner::{Miner, MinerService}; //! //! fn main() { //! let miner: Miner = Miner::default(); @@ -43,30 +42,21 @@ //! } //! ``` - -#[macro_use] -extern crate log; -#[macro_use] -extern crate ethcore_util as util; -extern crate ethcore; -extern crate env_logger; -extern crate rayon; - mod miner; mod external; mod transaction_queue; -pub use transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; -pub use miner::{Miner}; -pub use external::{ExternalMiner, ExternalMinerService}; +pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; +pub use self::miner::{Miner}; +pub use self::external::{ExternalMiner, ExternalMinerService}; use std::collections::BTreeMap; use util::{H256, U256, Address, Bytes}; -use ethcore::client::{ExtendedBlockChainClient, Executed}; -use ethcore::block::ClosedBlock; -use ethcore::receipt::Receipt; -use ethcore::error::{Error, ExecutionError}; -use ethcore::transaction::SignedTransaction; +use client::{ExtendedBlockChainClient, Executed}; +use block::ClosedBlock; +use receipt::Receipt; +use error::{Error, ExecutionError}; +use transaction::SignedTransaction; /// Miner client API pub trait MinerService : Send + Sync { diff --git a/miner/src/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs similarity index 99% rename from miner/src/transaction_queue.rs rename to ethcore/src/miner/transaction_queue.rs index fc62c411e..1b88a7a11 100644 --- a/miner/src/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -89,8 +89,8 @@ use std::collections::{HashMap, BTreeSet}; use util::numbers::{Uint, U256}; use util::hash::{Address, H256}; use util::table::*; -use ethcore::transaction::*; -use ethcore::error::{Error, TransactionError}; +use transaction::*; +use error::{Error, TransactionError}; /// Transaction origin #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 38bd873b8..e82f6725b 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -21,6 +21,7 @@ use util::panics::*; use spec::Spec; use error::*; use client::{Client, ClientConfig}; +use miner::Miner; /// Message type for external and internal events #[derive(Clone)] @@ -54,14 +55,14 @@ pub struct ClientService { impl ClientService { /// Start the service in a separate thread. - pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { + pub fn start(config: ClientConfig, spec: Spec, net_config: NetworkConfiguration, db_path: &Path, miner: Arc) -> Result { let panic_handler = PanicHandler::new_in_arc(); let mut net_service = try!(NetworkService::start(net_config)); panic_handler.forward_from(&net_service); info!("Starting {}", net_service.host_info()); info!("Configured for {} using {:?} engine", spec.name, spec.engine.name()); - let client = try!(Client::new(config, spec, db_path, net_service.io().channel())); + let client = try!(Client::new(config, spec, db_path, miner, net_service.io().channel())); panic_handler.forward_from(client.deref()); let client_io = Arc::new(ClientIoHandler { client: client.clone() From a845e08bc6ab8f8f8073fd659e731c76b815cb6a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 20:33:26 +0200 Subject: [PATCH 61/88] rename of the trait --- ethcore/src/client/client.rs | 4 ++-- ethcore/src/client/mod.rs | 2 +- ethcore/src/client/test_client.rs | 4 ++-- ethcore/src/miner/miner.rs | 32 +++++++++++++++---------------- ethcore/src/miner/mod.rs | 24 +++++++++++------------ 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d23bffa31..6ff56b3ea 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,7 +37,7 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; -use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, ExtendedBlockChainClient, TraceFilter}; +use client::{BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient, MiningBlockChainClient, TraceFilter}; use client::Error as ClientError; use env_info::EnvInfo; use executive::{Executive, Executed, TransactOptions, contract_address}; @@ -722,7 +722,7 @@ impl BlockChainClient for Client where V: Verifier { } } -impl ExtendedBlockChainClient for Client where V: Verifier { +impl MiningBlockChainClient for Client where V: Verifier { fn prepare_sealing(&self, author: Address, gas_floor_target: U256, extra_data: Bytes, transactions: Vec) -> (Option, HashSet) { let engine = self.engine.deref().deref(); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 67c753d46..209a9f6e2 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -185,7 +185,7 @@ pub trait BlockChainClient : Sync + Send { } /// Extended client interface used for mining -pub trait ExtendedBlockChainClient : BlockChainClient { +pub trait MiningBlockChainClient : BlockChainClient { /// Attempts to seal given block. Returns `SealedBlock` on success and the same block in case of error. fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index ad398bbcb..fd392f025 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -20,7 +20,7 @@ use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; -use client::{BlockChainClient, ExtendedBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes}; +use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, TransactionID, UncleID, TraceId, TraceFilter, LastHashes}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -235,7 +235,7 @@ impl TestBlockChainClient { } } -impl ExtendedBlockChainClient for TestBlockChainClient { +impl MiningBlockChainClient for TestBlockChainClient { fn try_seal(&self, block: LockedBlock, _seal: Vec) -> Result { Err(block) } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index c4bec7659..5f49a38c9 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -20,7 +20,7 @@ use std::sync::atomic::AtomicBool; use util::*; use util::keys::store::{AccountService, AccountProvider}; use views::{BlockView, HeaderView}; -use client::{ExtendedBlockChainClient, BlockID}; +use client::{MiningBlockChainClient, BlockID}; use block::{ClosedBlock, IsBlock}; use error::*; use client::{Executive, Executed, EnvInfo, TransactOptions}; @@ -104,7 +104,7 @@ impl Miner { /// Prepares new block for sealing including top transactions from queue. #[cfg_attr(feature="dev", allow(match_same_arms))] #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] - fn prepare_sealing(&self, chain: &ExtendedBlockChainClient) { + fn prepare_sealing(&self, chain: &MiningBlockChainClient) { trace!(target: "miner", "prepare_sealing: entering"); let transactions = self.transaction_queue.lock().unwrap().top_transactions(); let mut sealing_work = self.sealing_work.lock().unwrap(); @@ -206,14 +206,14 @@ impl Miner { trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash())); } - fn update_gas_limit(&self, chain: &ExtendedBlockChainClient) { + fn update_gas_limit(&self, chain: &MiningBlockChainClient) { let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); let mut queue = self.transaction_queue.lock().unwrap(); queue.set_gas_limit(gas_limit); } /// Returns true if we had to prepare new pending block - fn enable_and_prepare_sealing(&self, chain: &ExtendedBlockChainClient) -> bool { + fn enable_and_prepare_sealing(&self, chain: &MiningBlockChainClient) -> bool { trace!(target: "miner", "enable_and_prepare_sealing: entering"); let have_work = self.sealing_work.lock().unwrap().peek_last_ref().is_some(); trace!(target: "miner", "enable_and_prepare_sealing: have_work={}", have_work); @@ -237,7 +237,7 @@ const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; impl MinerService for Miner { - fn clear_and_reset(&self, chain: &ExtendedBlockChainClient) { + fn clear_and_reset(&self, chain: &MiningBlockChainClient) { self.transaction_queue.lock().unwrap().clear(); self.update_sealing(chain); } @@ -252,7 +252,7 @@ impl MinerService for Miner { } } - fn call(&self, chain: &ExtendedBlockChainClient, t: &SignedTransaction) -> Result { + fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction) -> Result { let sealing_work = self.sealing_work.lock().unwrap(); match sealing_work.peek_last_ref() { Some(work) => { @@ -288,7 +288,7 @@ impl MinerService for Miner { } } - fn balance(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256 { + fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else( || chain.latest_balance(address), @@ -296,7 +296,7 @@ impl MinerService for Miner { ) } - fn storage_at(&self, chain: &ExtendedBlockChainClient, address: &Address, position: &H256) -> H256 { + fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else( || chain.latest_storage_at(address, position), @@ -304,12 +304,12 @@ impl MinerService for Miner { ) } - fn nonce(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256 { + fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256 { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else(|| chain.latest_nonce(address), |b| b.block().fields().state.nonce(address)) } - fn code(&self, chain: &ExtendedBlockChainClient, address: &Address) -> Option { + fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option { let sealing_work = self.sealing_work.lock().unwrap(); sealing_work.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address)) } @@ -376,7 +376,7 @@ impl MinerService for Miner { .collect() } - fn import_own_transaction(&self, chain: &ExtendedBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> + fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails { let hash = transaction.hash(); @@ -470,7 +470,7 @@ impl MinerService for Miner { self.transaction_queue.lock().unwrap().last_nonce(address) } - fn update_sealing(&self, chain: &ExtendedBlockChainClient) { + fn update_sealing(&self, chain: &MiningBlockChainClient) { if self.sealing_enabled.load(atomic::Ordering::Relaxed) { let current_no = chain.chain_info().best_block_number; let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions(); @@ -490,7 +490,7 @@ impl MinerService for Miner { } } - fn map_sealing_work(&self, chain: &ExtendedBlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { + fn map_sealing_work(&self, chain: &MiningBlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { trace!(target: "miner", "map_sealing_work: entering"); self.enable_and_prepare_sealing(chain); trace!(target: "miner", "map_sealing_work: sealing prepared"); @@ -500,7 +500,7 @@ impl MinerService for Miner { ret.map(f) } - fn submit_seal(&self, chain: &ExtendedBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { if let Some(b) = self.sealing_work.lock().unwrap().take_used_if(|b| &b.hash() == &pow_hash) { match chain.try_seal(b.lock(), seal) { Err(_) => { @@ -523,8 +523,8 @@ impl MinerService for Miner { } } - fn chain_new_blocks(&self, chain: &ExtendedBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { - fn fetch_transactions(chain: &ExtendedBlockChainClient, hash: &H256) -> Vec { + fn chain_new_blocks(&self, chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) { + fn fetch_transactions(chain: &MiningBlockChainClient, hash: &H256) -> Vec { let block = chain .block(BlockID::Hash(*hash)) // Client should send message after commit to db and inserting to chain. diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 95453027c..824b1f51b 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -52,7 +52,7 @@ pub use self::external::{ExternalMiner, ExternalMinerService}; use std::collections::BTreeMap; use util::{H256, U256, Address, Bytes}; -use client::{ExtendedBlockChainClient, Executed}; +use client::{MiningBlockChainClient, Executed}; use block::ClosedBlock; use receipt::Receipt; use error::{Error, ExecutionError}; @@ -100,7 +100,7 @@ pub trait MinerService : Send + Sync { where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Imports own (node owner) transaction to queue. - fn import_own_transaction(&self, chain: &ExtendedBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> + fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails, Self: Sized; @@ -108,20 +108,20 @@ pub trait MinerService : Send + Sync { fn pending_transactions_hashes(&self) -> Vec; /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, chain: &ExtendedBlockChainClient); + fn clear_and_reset(&self, chain: &MiningBlockChainClient); /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, chain: &ExtendedBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); + fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]); /// New chain head event. Restart mining operation. - fn update_sealing(&self, chain: &ExtendedBlockChainClient); + fn update_sealing(&self, chain: &MiningBlockChainClient); /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &ExtendedBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; + fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, chain: &ExtendedBlockChainClient, f: F) -> Option + fn map_sealing_work(&self, chain: &MiningBlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T, Self: Sized; /// Query pending transactions for hash. @@ -146,19 +146,19 @@ pub trait MinerService : Send + Sync { fn sensible_gas_limit(&self) -> U256 { x!(21000) } /// Latest account balance in pending state. - fn balance(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256; + fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256; /// Call into contract code using pending state. - fn call(&self, chain: &ExtendedBlockChainClient, t: &SignedTransaction) -> Result; + fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction) -> Result; /// Get storage value in pending state. - fn storage_at(&self, chain: &ExtendedBlockChainClient, address: &Address, position: &H256) -> H256; + fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256; /// Get account nonce in pending state. - fn nonce(&self, chain: &ExtendedBlockChainClient, address: &Address) -> U256; + fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> U256; /// Get contract code in pending state. - fn code(&self, chain: &ExtendedBlockChainClient, address: &Address) -> Option; + fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option; } /// Mining status From f5ed31792fcd6daa252e748725c243c106edd55f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 20:54:02 +0200 Subject: [PATCH 62/88] fixed sync with client only --- Cargo.lock | 18 +----------------- Cargo.toml | 3 +-- miner/Cargo.toml | 24 ------------------------ miner/build.rs | 25 ------------------------- rpc/Cargo.toml | 3 +-- sync/Cargo.toml | 3 +-- sync/src/chain.rs | 10 +++------- sync/src/io.rs | 8 ++++---- sync/src/lib.rs | 6 ++---- sync/src/tests/helpers.rs | 1 - 10 files changed, 13 insertions(+), 88 deletions(-) delete mode 100644 miner/Cargo.toml delete mode 100644 miner/build.rs diff --git a/Cargo.lock b/Cargo.lock index cc2a8ef8c..291e90562 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,6 @@ dependencies = [ "ethcore-rpc 1.2.0", "ethcore-signer 1.2.0", "ethcore-util 1.2.0", - "ethminer 1.2.0", "ethsync 1.2.0", "fdlimit 0.1.0", "hyper 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -255,6 +254,7 @@ dependencies = [ "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.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)", @@ -334,7 +334,6 @@ dependencies = [ "ethcore-devtools 1.2.0", "ethcore-util 1.2.0", "ethjson 0.1.0", - "ethminer 1.2.0", "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)", @@ -415,20 +414,6 @@ dependencies = [ "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethminer" -version = "1.2.0" -dependencies = [ - "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore 1.2.0", - "ethcore-util 1.2.0", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethsync" version = "1.2.0" @@ -437,7 +422,6 @@ dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.2.0", "ethcore-util 1.2.0", - "ethminer 1.2.0", "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index d7813468a..ce8823bd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ clippy = { version = "0.0.69", optional = true} ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } -ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } ethcore-signer = { path = "signer", optional = true } @@ -46,7 +45,7 @@ default-features = false default = ["rpc", "dapps", "ethcore-signer"] rpc = ["ethcore-rpc"] dapps = ["ethcore-dapps"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"] travis-beta = ["ethcore/json-tests"] travis-nightly = ["ethcore/json-tests", "dev"] diff --git a/miner/Cargo.toml b/miner/Cargo.toml deleted file mode 100644 index a3a1c059f..000000000 --- a/miner/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -description = "Ethminer library" -homepage = "http://ethcore.io" -license = "GPL-3.0" -name = "ethminer" -version = "1.2.0" -authors = ["Ethcore "] -build = "build.rs" - -[build-dependencies] -rustc_version = "0.1" - -[dependencies] -ethcore-util = { path = "../util" } -ethcore = { path = "../ethcore" } -log = "0.3" -env_logger = "0.3" -rustc-serialize = "0.3" -rayon = "0.3.1" -clippy = { version = "0.0.69", optional = true} - -[features] -default = [] -dev = ["clippy"] diff --git a/miner/build.rs b/miner/build.rs deleted file mode 100644 index 41b9a1b3e..000000000 --- a/miner/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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 rustc_version; - -use rustc_version::{version_meta, Channel}; - -fn main() { - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 61b51cf88..2dbefd7f4 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,7 +18,6 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } -ethminer = { path = "../miner" } ethjson = { path = "../json" } ethcore-devtools = { path = "../devtools" } rustc-serialize = "0.3" @@ -34,4 +33,4 @@ syntex = "^0.32.0" [features] default = ["serde_codegen"] nightly = ["serde_macros"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethminer/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 7940aaa2d..1b80e23fc 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -11,7 +11,6 @@ authors = ["Ethcore , /// Network ID network_id: U256, - /// Miner - miner: Arc, } type RlpResponseResult = Result, PacketDecodeError>; impl ChainSync { /// Create a new instance of syncing strategy. - pub fn new(config: SyncConfig, miner: Arc, chain: &BlockChainClient) -> ChainSync { + pub fn new(config: SyncConfig, chain: &BlockChainClient) -> ChainSync { let chain = chain.chain_info(); let mut sync = ChainSync { state: SyncState::ChainHead, @@ -265,7 +263,6 @@ impl ChainSync { imported_this_round: None, _max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, - miner: miner, }; sync.reset(); sync @@ -903,7 +900,7 @@ impl ChainSync { nonce: chain.latest_nonce(a), balance: chain.latest_balance(a), }; - let _ = io.chain().import_transactions(transactions, fetch_account); + let _ = io.chain().import_transactions(transactions); Ok(()) } @@ -1288,7 +1285,6 @@ mod tests { use ethcore::header::*; use ethcore::client::*; use ethcore::spec::Spec; - use ethminer::{Miner, MinerService}; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); diff --git a/sync/src/io.rs b/sync/src/io.rs index 49cccd7ca..53a546e1c 100644 --- a/sync/src/io.rs +++ b/sync/src/io.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethcore::client::MiningClient; use util::{NetworkContext, PeerId, PacketId,}; use util::error::UtilError; use ethcore::service::SyncMessage; +use ethcore::client::BlockChainClient; /// IO interface for the syning handler. /// Provides peer connection management and an interface to the blockchain client. @@ -32,7 +32,7 @@ pub trait SyncIo { /// Send a packet to a peer. fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec) -> Result<(), UtilError>; /// Get the blockchain - fn chain(&self) -> &MiningClient; + fn chain(&self) -> &BlockChainClient; /// Returns peer client identifier string fn peer_info(&self, peer_id: PeerId) -> String { peer_id.to_string() @@ -46,12 +46,12 @@ pub trait SyncIo { /// Wraps `NetworkContext` and the blockchain client pub struct NetSyncIo<'s, 'h> where 'h: 's { network: &'s NetworkContext<'h, SyncMessage>, - chain: &'s MiningClient + chain: &'s BlockChainClient } impl<'s, 'h> NetSyncIo<'s, 'h> { /// Creates a new instance from the `NetworkContext` and the blockchain client reference. - pub fn new(network: &'s NetworkContext<'h, SyncMessage>, chain: &'s MiningClient) -> NetSyncIo<'s, 'h> { + pub fn new(network: &'s NetworkContext<'h, SyncMessage>, chain: &'s BlockChainClient) -> NetSyncIo<'s, 'h> { NetSyncIo { network: network, chain: chain, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 6b72a24fc..9fa6501a2 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -55,7 +55,6 @@ extern crate log; #[macro_use] extern crate ethcore_util as util; extern crate ethcore; -extern crate ethminer; extern crate env_logger; extern crate time; extern crate rand; @@ -69,7 +68,6 @@ use util::TimerToken; use util::{U256, ONE_U256}; use ethcore::client::Client; use ethcore::service::SyncMessage; -use ethminer::Miner; use io::NetSyncIo; use chain::ChainSync; @@ -115,8 +113,8 @@ pub use self::chain::{SyncStatus, SyncState}; impl EthSync { /// Creates and register protocol with the network service - pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc, miner: Arc) -> Arc { - let sync = ChainSync::new(config, miner, chain.deref()); + pub fn register(service: &mut NetworkService, config: SyncConfig, chain: Arc) -> Arc { + let sync = ChainSync::new(config, chain.deref()); let sync = Arc::new(EthSync { chain: chain, sync: RwLock::new(sync), diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 70ddb78db..c2e0e2d04 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -19,7 +19,6 @@ use ethcore::client::{TestBlockChainClient, BlockChainClient}; use ethcore::spec::Spec; use io::SyncIo; use chain::ChainSync; -use ethminer::Miner; use ::SyncConfig; pub struct TestIo<'p> { From 10d914d6c663a0f9bb9b2d517bebee7ae3115832 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 20:58:33 +0200 Subject: [PATCH 63/88] restored chain_new_blocks --- sync/src/chain.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 42d425af9..1270f775f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1272,6 +1272,18 @@ impl ChainSync { pub fn maintain_sync(&mut self, io: &mut SyncIo) { self.check_resume(io); } + + /// called when block is imported to chain, updates transactions queue and propagates the blocks + pub fn chain_new_blocks(&mut self, io: &mut SyncIo, _imported: &[H256], invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { + if io.is_chain_queue_empty() { + // Propagate latests blocks + self.propagate_latest_blocks(io); + } + if !invalid.is_empty() { + trace!(target: "sync", "Bad blocks in the queue, restarting"); + self.restart_on_bad_block(io); + } + } } #[cfg(test)] From ec7af964ab75f6c6e12a1449684bf0b5fa233e3a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 21:01:47 +0200 Subject: [PATCH 64/88] correct map macro invocation --- ethcore/src/pod_account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 96642d1f8..65146296a 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -171,7 +171,7 @@ mod test { 3.into() => Diff::new(3.into(), 0.into()), 4.into() => Diff::new(4.into(), 0.into()), 7.into() => Diff::new(0.into(), 7.into()), - 9.into() => Diff::new(0.into(), 9.into()), + 9.into() => Diff::new(0.into(), 9.into()) ], })); } From 495e7feb62807ec90f3548cfae16d606453d05fc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 21:13:32 +0200 Subject: [PATCH 65/88] dispatching message return --- sync/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 9fa6501a2..863ad6382 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -164,5 +164,12 @@ impl NetworkProtocolHandler for EthSync { } fn message(&self, io: &NetworkContext, message: &SyncMessage) { + match *message { + SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => { + let mut sync_io = NetSyncIo::new(io, self.chain.deref()); + self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted); + }, + _ => {/* Ignore other messages */}, + } } } From 2a08fb8fe3ffaff3de41aa7427ba5c38c1559232 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 21:17:46 +0200 Subject: [PATCH 66/88] and conditional dispatch --- ethcore/src/client/client.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6ff56b3ea..4df72f1fd 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -338,7 +338,17 @@ impl Client where V: Verifier { { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() { let (enacted, retracted) = self.calculate_enacted_retracted(import_results); - self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted); + + if self.queue_info().is_empty() { + self.miner.chain_new_blocks(self, &imported_blocks, &invalid_blocks, &enacted, &retracted); + } + + io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { + imported: imported_blocks, + invalid: invalid_blocks, + enacted: enacted, + retracted: retracted, + })).unwrap(); } } From 4146e1f02b45f548834a4e3507420ec18b725046 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 21:18:54 +0200 Subject: [PATCH 67/88] add empty rule to map macros --- util/src/common.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/src/common.rs b/util/src/common.rs index 2eb2ea017..0e0cd7757 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -26,6 +26,7 @@ pub use sha3::*; #[macro_export] macro_rules! hash_map { + () => { HashMap::new() }; ( $( $x:expr => $y:expr ),* ) => {{ let mut x = HashMap::new(); $( @@ -37,6 +38,7 @@ macro_rules! hash_map { #[macro_export] macro_rules! hash_map_into { + () => { HashMap::new() }; ( $( $x:expr => $y:expr ),* ) => {{ let mut x = HashMap::new(); $( @@ -48,6 +50,7 @@ macro_rules! hash_map_into { #[macro_export] macro_rules! map { + () => { BTreeMap::new() }; ( $( $x:expr => $y:expr ),* ) => {{ let mut x = BTreeMap::new(); $( @@ -59,6 +62,7 @@ macro_rules! map { #[macro_export] macro_rules! map_into { + () => { BTreeMap::new() }; ( $( $x:expr => $y:expr ),* ) => {{ let mut x = BTreeMap::new(); $( From 77cef765183491e69d53210258824c43e22bf5d0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 21:31:42 +0200 Subject: [PATCH 68/88] rpc bindings resolved --- parity/dapps.rs | 2 +- parity/main.rs | 2 +- parity/rpc.rs | 2 +- parity/signer.rs | 2 +- rpc/src/lib.rs | 1 - rpc/src/v1/impls/eth.rs | 16 +++++++------- rpc/src/v1/impls/ethcore.rs | 2 +- rpc/src/v1/impls/mod.rs | 10 ++++----- rpc/src/v1/impls/personal.rs | 10 ++++----- rpc/src/v1/tests/eth.rs | 6 +++--- rpc/src/v1/tests/helpers/miner_service.rs | 26 +++++++++++------------ rpc/src/v1/tests/mocked/eth.rs | 2 +- rpc/src/v1/tests/mocked/ethcore.rs | 2 +- sync/src/chain.rs | 2 +- sync/src/tests/helpers.rs | 2 +- 15 files changed, 43 insertions(+), 44 deletions(-) diff --git a/parity/dapps.rs b/parity/dapps.rs index 986e3dd07..7909bb9bc 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -19,7 +19,7 @@ use std::str::FromStr; use std::net::SocketAddr; use ethcore::client::Client; use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; +use ethcore::miner::{Miner, ExternalMiner}; use util::RotatingLogger; use util::panics::PanicHandler; use util::keys::store::AccountService; diff --git a/parity/main.rs b/parity/main.rs index 7f16d28a5..539797fb9 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -85,7 +85,7 @@ use ethcore::error::{Error, ImportError}; use ethcore::service::ClientService; use ethcore::spec::Spec; use ethsync::EthSync; -use ethminer::{Miner, MinerService, ExternalMiner}; +use ethcore::miner::{Miner, MinerService, ExternalMiner}; use daemonize::Daemonize; use migration::migrate; use informant::Informant; diff --git a/parity/rpc.rs b/parity/rpc.rs index 60766263b..0d8d7562e 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use std::net::SocketAddr; use ethcore::client::Client; use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; +use ethcore::miner::{Miner, ExternalMiner}; use util::RotatingLogger; use util::panics::PanicHandler; use util::keys::store::AccountService; diff --git a/parity/signer.rs b/parity/signer.rs index 5e3339bcc..3f6197e3a 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use ethcore::client::Client; use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; +use ethcore::miner::{Miner, ExternalMiner}; use util::keys::store::AccountService; use util::panics::{PanicHandler, ForwardPanic}; use die::*; diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 24d58819c..80c92388a 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -29,7 +29,6 @@ extern crate jsonrpc_http_server; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; -extern crate ethminer; extern crate transient_hashmap; extern crate json_ipc_server as ipc; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a57fc333c..ad15fb2f7 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,13 +22,13 @@ use std::collections::HashSet; use std::sync::{Arc, Weak, Mutex}; use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; -use ethminer::{MinerService, ExternalMinerService}; +use ethcore::miner::{MinerService, ExternalMinerService}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; use util::rlp::{encode, decode, UntrustedRlp, View}; use util::keys::store::AccountProvider; -use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID}; +use ethcore::client::{MiningBlockChainClient, BlockID, TransactionID, UncleID}; use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash; @@ -44,7 +44,7 @@ use serde; /// Eth rpc implementation. pub struct EthClient where - C: BlockChainClient, + C: MiningBlockChainClient, S: SyncProvider, A: AccountProvider, M: MinerService, @@ -59,7 +59,7 @@ pub struct EthClient where } impl EthClient where - C: BlockChainClient, + C: MiningBlockChainClient, S: SyncProvider, A: AccountProvider, M: MinerService, @@ -224,7 +224,7 @@ fn make_unsupported_err() -> Error { } impl Eth for EthClient where - C: BlockChainClient + 'static, + C: MiningBlockChainClient + 'static, S: SyncProvider + 'static, A: AccountProvider + 'static, M: MinerService + 'static, @@ -566,7 +566,7 @@ impl Eth for EthClient where /// Eth filter rpc implementation. pub struct EthFilterClient where - C: BlockChainClient, + C: MiningBlockChainClient, M: MinerService { client: Weak, @@ -575,7 +575,7 @@ pub struct EthFilterClient where } impl EthFilterClient where - C: BlockChainClient, + C: MiningBlockChainClient, M: MinerService { /// Creates new Eth filter client. @@ -589,7 +589,7 @@ impl EthFilterClient where } impl EthFilter for EthFilterClient where - C: BlockChainClient + 'static, + C: MiningBlockChainClient + 'static, M: MinerService + 'static { fn new_filter(&self, params: Params) -> Result { diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index f5d6f1fda..e649e37f4 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -22,7 +22,7 @@ use std::sync::{Arc, Weak}; use std::ops::Deref; use std::collections::BTreeMap; use jsonrpc_core::*; -use ethminer::MinerService; +use ethcore::miner::MinerService; use v1::traits::Ethcore; use v1::types::Bytes; diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 7ee8b8b8a..2f1c07ff6 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -47,8 +47,8 @@ pub use self::rpc::RpcClient; use v1::types::TransactionRequest; use std::sync::Weak; -use ethminer::{AccountDetails, MinerService}; -use ethcore::client::BlockChainClient; +use ethcore::miner::{AccountDetails, MinerService}; +use ethcore::client::MiningBlockChainClient; use ethcore::transaction::{Action, SignedTransaction, Transaction}; use util::numbers::*; use util::rlp::encode; @@ -56,7 +56,7 @@ use util::bytes::ToPretty; use jsonrpc_core::{Error, to_value, Value}; fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result - where C: BlockChainClient, M: MinerService { + where C: MiningBlockChainClient, M: MinerService { let hash = signed_transaction.hash(); let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| { @@ -70,7 +70,7 @@ fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedT } fn sign_and_dispatch(client: &Weak, miner: &Weak, request: TransactionRequest, secret: H256) -> Result - where C: BlockChainClient, M: MinerService { + where C: MiningBlockChainClient, M: MinerService { let client = take_weak!(client); let miner = take_weak!(miner); @@ -92,4 +92,4 @@ fn sign_and_dispatch(client: &Weak, miner: &Weak, request: Transacti trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); dispatch_transaction(&*client, &*miner, signed_transaction) -} \ No newline at end of file +} diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 19e902996..074bb8c77 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -22,19 +22,19 @@ use v1::types::TransactionRequest; use v1::impls::sign_and_dispatch; use util::keys::store::*; use util::numbers::*; -use ethcore::client::BlockChainClient; -use ethminer::MinerService; +use ethcore::client::MiningBlockChainClient; +use ethcore::miner::MinerService; /// Account management (personal) rpc implementation. pub struct PersonalClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { accounts: Weak, client: Weak, miner: Weak, } impl PersonalClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { /// Creates new PersonalClient pub fn new(store: &Arc, client: &Arc, miner: &Arc) -> Self { PersonalClient { @@ -46,7 +46,7 @@ impl PersonalClient } impl Personal for PersonalClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { fn accounts(&self, _: Params) -> Result { let store = take_weak!(self.accounts); match store.accounts() { diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 80a856aca..7f5d5e333 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,12 +19,12 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; -use ethcore::client::{BlockChainClient, Client, ClientConfig}; +use ethcore::client::{MiningBlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; use ethcore::ethereum; use ethcore::transaction::{Transaction, Action}; -use ethminer::{MinerService, ExternalMiner}; +use ethcore::miner::{MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; use util::hash::Address; @@ -38,7 +38,7 @@ use v1::impls::EthClient; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; struct EthTester { - _client: Arc, + _client: Arc, _miner: Arc, accounts: Arc, handler: IoHandler, diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 600f88508..a53ca3a08 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -19,11 +19,11 @@ use util::{Address, H256, Bytes, U256, FixedHash, Uint}; use util::standard::*; use ethcore::error::{Error, ExecutionError}; -use ethcore::client::{BlockChainClient, Executed}; +use ethcore::client::{MiningBlockChainClient, Executed}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::transaction::SignedTransaction; use ethcore::receipt::Receipt; -use ethminer::{MinerService, MinerStatus, AccountDetails, TransactionImportResult}; +use ethcore::miner::{MinerService, MinerStatus, AccountDetails, TransactionImportResult}; /// Test miner service. pub struct TestMinerService { @@ -132,7 +132,7 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> + fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails { @@ -154,21 +154,21 @@ impl MinerService for TestMinerService { } /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, _chain: &BlockChainClient) { + fn clear_and_reset(&self, _chain: &MiningBlockChainClient) { unimplemented!(); } /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { + fn chain_new_blocks(&self, _chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } /// New chain head event. Restart mining operation. - fn update_sealing(&self, _chain: &BlockChainClient) { + fn update_sealing(&self, _chain: &MiningBlockChainClient) { unimplemented!(); } - fn map_sealing_work(&self, _chain: &BlockChainClient, _f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { + fn map_sealing_work(&self, _chain: &MiningBlockChainClient, _f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { unimplemented!(); } @@ -194,29 +194,29 @@ impl MinerService for TestMinerService { /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, _chain: &MiningBlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } - fn balance(&self, _chain: &BlockChainClient, address: &Address) -> U256 { + fn balance(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 { 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: &MiningBlockChainClient, _t: &SignedTransaction) -> Result { unimplemented!(); } - fn storage_at(&self, _chain: &BlockChainClient, address: &Address, position: &H256) -> H256 { + fn storage_at(&self, _chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256 { self.latest_closed_block.lock().unwrap().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone()) } - fn nonce(&self, _chain: &BlockChainClient, address: &Address) -> U256 { + fn nonce(&self, _chain: &MiningBlockChainClient, address: &Address) -> U256 { // we assume all transactions are in a pending block, ignoring the // reality of gas limits. self.last_nonce(address).unwrap_or(U256::zero()) } - fn code(&self, _chain: &BlockChainClient, address: &Address) -> Option { + fn code(&self, _chain: &MiningBlockChainClient, address: &Address) -> Option { self.latest_closed_block.lock().unwrap().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone()) } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index c51d6d7da..579f57e6c 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -25,7 +25,7 @@ use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, Transaction use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; -use ethminer::{ExternalMiner, MinerService}; +use ethcore::miner::{ExternalMiner, MinerService}; use ethsync::SyncState; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index cc822daef..d51545d86 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::str::FromStr; use jsonrpc_core::IoHandler; use v1::{Ethcore, EthcoreClient}; -use ethminer::MinerService; +use ethcore::miner::MinerService; use v1::tests::helpers::TestMinerService; use util::numbers::*; use rustc_serialize::hex::FromHex; diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 1270f775f..dc397d77d 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1470,7 +1470,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test()), client); + let mut sync = ChainSync::new(SyncConfig::default(), client); sync.peers.insert(0, PeerInfo { protocol_version: 0, diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index c2e0e2d04..7cde0b54c 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -92,7 +92,7 @@ impl TestNet { }; for _ in 0..n { let chain = TestBlockChainClient::new(); - let sync = ChainSync::new(SyncConfig::default(), Miner::new(false, Spec::new_test()), &chain); + let sync = ChainSync::new(SyncConfig::default(), &chain); net.peers.push(TestPeer { sync: sync, chain: chain, From bbb858b3862856bf1d18b559b263075be0149d89 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 21:38:05 +0200 Subject: [PATCH 69/88] address small syntax breakages --- ethcore/src/state.rs | 24 ++++++++++++------------ ethcore/src/state_diff.rs | 8 ++++---- ethcore/src/tests/helpers.rs | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 6e0e4f2f6..c099b17a5 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -389,7 +389,7 @@ fn should_apply_create_transaction() { data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -450,7 +450,7 @@ fn should_trace_failed_create_transaction() { data: FromHex::from_hex("5b600056").unwrap(), }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -489,7 +489,7 @@ fn should_trace_call_transaction() { }.sign(&"".sha3()); state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -531,7 +531,7 @@ fn should_trace_basic_call_transaction() { data: vec![], }.sign(&"".sha3()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -745,7 +745,7 @@ fn should_trace_failed_call_transaction() { }.sign(&"".sha3()); state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -788,7 +788,7 @@ fn should_trace_call_with_subcall_transaction() { state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -845,7 +845,7 @@ fn should_trace_call_with_basic_subcall_transaction() { }.sign(&"".sha3()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -899,7 +899,7 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() { }.sign(&"".sha3()); state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -943,7 +943,7 @@ fn should_trace_failed_subcall_transaction() { state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -999,7 +999,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { @@ -1032,7 +1032,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { depth: 2, action: trace::Action::Call(trace::Call { from: 0xb.into(), - to: 0xb.into(), + to: 0xc.into(), value: 0.into(), gas: 78868.into(), input: vec![], @@ -1072,7 +1072,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() { state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = Some(Trace { diff --git a/ethcore/src/state_diff.rs b/ethcore/src/state_diff.rs index 1c1975e70..c362d96d1 100644 --- a/ethcore/src/state_diff.rs +++ b/ethcore/src/state_diff.rs @@ -83,7 +83,7 @@ mod test { let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); let b = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]), - 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) + 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![ 2.into() => AccountDiff{ @@ -107,11 +107,11 @@ mod test { fn change_with_unchanged() { let a = PodState::from(map![ 1.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]), - 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) + 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); let b = PodState::from(map![ - 1.into() => PodAccount::new(69.into(), 1.into(),, vec![], map![]), - 2.into() => PodAccount::new(69.into(), 0.into(),, vec![], map![]) + 1.into() => PodAccount::new(69.into(), 1.into(), vec![], map![]), + 2.into() => PodAccount::new(69.into(), 0.into(), vec![], map![]) ]); assert_eq!(StateDiff::diff_pod(&a, &b), StateDiff(map![ 1.into() => AccountDiff{ diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 6a370e49f..22282ccdd 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -99,7 +99,7 @@ pub fn create_test_block(header: &Header) -> Bytes { fn create_unverifiable_block_header(order: u32, parent_hash: H256) -> Header { let mut header = Header::new(); header.gas_limit = 0.into(); - header.difficulty = order * 100.into(); + header.difficulty = (order * 100).into(); header.timestamp = (order * 10) as u64; header.number = order as u64; header.parent_hash = parent_hash; From c33b1caf21d67ce3f5b56b2894ec000ff10a79e7 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 21:38:07 +0200 Subject: [PATCH 70/88] executable all issues resolved --- parity/main.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 539797fb9..0575d80ea 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -27,7 +27,6 @@ extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; -extern crate ethminer; #[macro_use] extern crate log as rlog; extern crate env_logger; @@ -173,14 +172,6 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) // Secret Store let account_service = Arc::new(conf.account_service()); - // Build client - let mut service = ClientService::start( - client_config, spec, net_settings, Path::new(&conf.path()) - ).unwrap_or_else(|e| die_with_error("Client", e)); - - panic_handler.forward_from(&service); - let client = service.client(); - // Miner let miner = Miner::with_accounts(conf.args.flag_force_sealing, conf.spec(), account_service.clone()); miner.set_author(conf.author()); @@ -189,11 +180,19 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) miner.set_minimal_gas_price(conf.gas_price()); miner.set_transactions_limit(conf.args.flag_tx_limit); + // Build client + let mut service = ClientService::start( + client_config, spec, net_settings, Path::new(&conf.path()), miner.clone() + ).unwrap_or_else(|e| die_with_error("Client", e)); + + panic_handler.forward_from(&service); + let client = service.client(); + let external_miner = Arc::new(ExternalMiner::default()); let network_settings = Arc::new(conf.network_settings()); // Sync - let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); + let sync = EthSync::register(service.network(), sync_config, client.clone()); let dependencies = Arc::new(rpc::Dependencies { panic_handler: panic_handler.clone(), @@ -295,7 +294,7 @@ fn execute_export(conf: Configuration) { // Build client let service = ClientService::start( - client_config, spec, net_settings, Path::new(&conf.path()) + client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()), ).unwrap_or_else(|e| die_with_error("Client", e)); panic_handler.forward_from(&service); @@ -366,7 +365,7 @@ fn execute_import(conf: Configuration) { // Build client let service = ClientService::start( - client_config, spec, net_settings, Path::new(&conf.path()) + client_config, spec, net_settings, Path::new(&conf.path()), Arc::new(Miner::default()), ).unwrap_or_else(|e| die_with_error("Client", e)); panic_handler.forward_from(&service); From 99573286074b3daebf1690fb30a9397c495e27ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 31 May 2016 21:39:11 +0200 Subject: [PATCH 71/88] DENY frames from other origins to prevent clickjacking --- dapps/src/apps.rs | 6 ++++-- dapps/src/page/mod.rs | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dapps/src/apps.rs b/dapps/src/apps.rs index 559282584..28f1979bf 100644 --- a/dapps/src/apps.rs +++ b/dapps/src/apps.rs @@ -38,11 +38,13 @@ pub fn utils() -> Box { pub fn all_endpoints() -> Endpoints { let mut pages = Endpoints::new(); - pages.insert("proxy".to_owned(), ProxyPac::boxed()); + pages.insert("proxy".into(), ProxyPac::boxed()); + pages.insert("home".into(), Box::new( + PageEndpoint::new_safe_to_embed(parity_dapps_builtins::App::default()) + )); insert::(&mut pages, "status"); insert::(&mut pages, "parity"); - insert::(&mut pages, "home"); wallet_page(&mut pages); daodapp_page(&mut pages); diff --git a/dapps/src/page/mod.rs b/dapps/src/page/mod.rs index 71989bca7..c7bfd83ec 100644 --- a/dapps/src/page/mod.rs +++ b/dapps/src/page/mod.rs @@ -30,6 +30,8 @@ pub struct PageEndpoint { pub app: Arc, /// Prefix to strip from the path (when `None` deducted from `app_id`) pub prefix: Option, + /// Safe to be loaded in frame by other origin. (use wisely!) + safe_to_embed: bool, } impl PageEndpoint { @@ -37,6 +39,7 @@ impl PageEndpoint { PageEndpoint { app: Arc::new(app), prefix: None, + safe_to_embed: false, } } @@ -44,6 +47,18 @@ impl PageEndpoint { PageEndpoint { app: Arc::new(app), prefix: Some(prefix), + safe_to_embed: false, + } + } + + /// Creates new `PageEndpoint` which can be safely used in iframe + /// even from different origin. It might be dangerous (clickjacking). + /// Use wisely! + pub fn new_safe_to_embed(app: T) -> Self { + PageEndpoint { + app: Arc::new(app), + prefix: None, + safe_to_embed: true, } } } @@ -61,6 +76,7 @@ impl Endpoint for PageEndpoint { path: path, file: None, write_pos: 0, + safe_to_embed: self.safe_to_embed, }) } } @@ -83,6 +99,7 @@ struct PageHandler { path: EndpointPath, file: Option, write_pos: usize, + safe_to_embed: bool, } impl PageHandler { @@ -128,6 +145,9 @@ impl server::Handler for PageHandler { 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())); + if !self.safe_to_embed { + res.headers_mut().set_raw("X-Frame-Options", vec![b"SAMEORIGIN".to_vec()]); + } Next::write() } else { res.set_status(StatusCode::NotFound); From dad61bb7cfb26f252a56236dcfb1368ffc64d676 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 21:40:26 +0200 Subject: [PATCH 72/88] test and travis fix for absent crate --- .travis.yml | 1 - test.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f0766ee4..995b765c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,7 +72,6 @@ after_success: | $KCOV_CMD target/debug/deps/ethcore_rpc-* && $KCOV_CMD target/debug/deps/ethcore_dapps-* && $KCOV_CMD target/debug/deps/ethcore_signer-* && - $KCOV_CMD target/debug/deps/ethminer-* && $KCOV_CMD target/debug/deps/ethjson-* && $KCOV_CMD target/debug/parity-* && [ $TRAVIS_BRANCH = master ] && diff --git a/test.sh b/test.sh index e70718afc..d89740aba 100755 --- a/test.sh +++ b/test.sh @@ -10,5 +10,4 @@ cargo test --features ethcore/json-tests $1 \ -p ethcore-signer \ -p ethcore-dapps \ -p parity \ - -p ethminer \ -p bigint From 5fd4b9d7bd74e641779864b05ce007bf23da008f Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 31 May 2016 21:50:25 +0200 Subject: [PATCH 73/88] formatting fix --- rpc/src/v1/tests/eth.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 0c159ceb2..30815b8a8 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -102,8 +102,13 @@ impl EthTester { let miner_service = miner_service(spec_provider(), account_provider.clone()); let external_miner = Arc::new(ExternalMiner::default()); - let eth_client = EthClient::new(&client, &sync_provider, &account_provider, - &miner_service, &external_miner); + let eth_client = EthClient::new( + &client, + &sync_provider, + &account_provider, + &miner_service, + &external_miner + ); let handler = IoHandler::new(); let delegate = eth_client.to_delegate(); From ae1bcd6a5b7880e10dae42b00c90300e3d9de6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 31 May 2016 21:50:34 +0200 Subject: [PATCH 74/88] Disabling ethcore APIs for RPC and IPC --- dapps/src/page/mod.rs | 1 + parity/cli.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dapps/src/page/mod.rs b/dapps/src/page/mod.rs index c7bfd83ec..819988310 100644 --- a/dapps/src/page/mod.rs +++ b/dapps/src/page/mod.rs @@ -212,6 +212,7 @@ fn should_extract_path_with_appid() { }, file: None, write_pos: 0, + safe_to_embed: true, }; // when diff --git a/parity/cli.rs b/parity/cli.rs index 60b622bf7..95b77a00d 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -76,13 +76,13 @@ API and Console Options: interface. APIS is a comma-delimited list of API name. Possible name are web3, eth, net, personal, ethcore, traces. - [default: web3,eth,net,personal,ethcore,traces]. + [default: web3,eth,net,personal,traces]. --ipc-off Disable JSON-RPC over IPC service. --ipc-path PATH Specify custom path for JSON-RPC over IPC service [default: $HOME/.parity/jsonrpc.ipc]. --ipc-apis APIS Specify custom API set available via JSON-RPC over - IPC [default: web3,eth,net,personal,ethcore]. + IPC [default: web3,eth,net,personal,traces]. --dapps-off Disable the Dapps server (e.g. status page). --dapps-port PORT Specify the port portion of the Dapps server From 67421fc69e3053ec5ed0c1d5bdb02711b50084b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 31 May 2016 21:56:41 +0200 Subject: [PATCH 75/88] Adding explanatory comment for safe_to_embed --- dapps/src/apps.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dapps/src/apps.rs b/dapps/src/apps.rs index 28f1979bf..130b20fb9 100644 --- a/dapps/src/apps.rs +++ b/dapps/src/apps.rs @@ -40,6 +40,9 @@ pub fn all_endpoints() -> Endpoints { let mut pages = Endpoints::new(); pages.insert("proxy".into(), ProxyPac::boxed()); + // Home page needs to be safe embed + // because we use Cross-Origin LocalStorage. + // TODO [ToDr] Account naming should be moved to parity. pages.insert("home".into(), Box::new( PageEndpoint::new_safe_to_embed(parity_dapps_builtins::App::default()) )); From d45a676dc0db78cb2ef3a85a2b7b3e647d950929 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Tue, 31 May 2016 22:24:32 +0200 Subject: [PATCH 76/88] all tests fixed --- ethcore/src/client/test_client.rs | 4 ++++ ethcore/src/json_tests/chain.rs | 3 ++- ethcore/src/miner/miner.rs | 8 ++++---- ethcore/src/miner/transaction_queue.rs | 4 ++-- ethcore/src/service.rs | 4 +++- ethcore/src/tests/client.rs | 9 +++++---- ethcore/src/tests/helpers.rs | 5 +++-- rpc/src/v1/tests/eth.rs | 6 +++--- sync/src/chain.rs | 15 ++++++++------- sync/src/tests/chain.rs | 2 +- sync/src/tests/helpers.rs | 4 ++-- 11 files changed, 37 insertions(+), 27 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fd392f025..fa91aab4a 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -28,6 +28,7 @@ use receipt::{Receipt, LocalizedReceipt}; use blockchain::extras::BlockReceipts; use error::{ImportResult}; use evm::Factory as EvmFactory; +use miner::Miner; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock, LockedBlock}; @@ -64,6 +65,8 @@ pub struct TestBlockChainClient { pub receipts: RwLock>, /// Block queue size. pub queue_size: AtomicUsize, + /// Miner + pub miner: Arc, } #[derive(Clone)] @@ -102,6 +105,7 @@ impl TestBlockChainClient { execution_result: RwLock::new(None), receipts: RwLock::new(HashMap::new()), queue_size: AtomicUsize::new(0), + miner: Arc::new(Miner::default()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index a1154f6a9..53052d8dc 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -22,6 +22,7 @@ use tests::helpers::*; use devtools::*; use spec::Genesis; use ethjson; +use miner::Miner; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); @@ -53,7 +54,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { let temp = RandomTempPath::new(); { - let client = Client::new(ClientConfig::default(), spec, temp.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), spec, temp.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); for b in &blockchain.blocks_rlp() { if Block::is_good(&b) { let _ = client.import_block(b.clone()); diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 5f49a38c9..66ede48bf 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -585,11 +585,11 @@ impl MinerService for Miner { #[cfg(test)] mod tests { - use MinerService; - use super::{Miner}; + use super::super::MinerService; + use super::Miner; use util::*; - use ethcore::client::{TestBlockChainClient, EachBlockWith}; - use ethcore::block::*; + use client::{TestBlockChainClient, EachBlockWith}; + use block::*; // TODO [ToDr] To uncomment` when TestBlockChainClient can actually return a ClosedBlock. #[ignore] diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 1b88a7a11..bf1512bde 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -778,8 +778,8 @@ mod test { extern crate rustc_serialize; use util::table::*; use util::*; - use ethcore::transaction::*; - use ethcore::error::{Error, TransactionError}; + use transaction::*; + use error::{Error, TransactionError}; use super::*; use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index e82f6725b..13f1c9f74 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -142,12 +142,14 @@ mod tests { use util::network::*; use devtools::*; use client::ClientConfig; + use std::sync::Arc; + use miner::Miner; #[test] fn it_can_be_started() { let spec = get_test_spec(); let temp_path = RandomTempPath::new(); - let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path()); + let service = ClientService::start(ClientConfig::default(), spec, NetworkConfiguration::new_local(), &temp_path.as_path(), Arc::new(Miner::default())); assert!(service.is_ok()); } } diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d734b0b47..84bfb716f 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -14,16 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient, Client, ClientConfig, BlockID}; +use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID}; use block::IsBlock; use tests::helpers::*; use common::*; use devtools::*; +use miner::Miner; #[test] fn imports_from_empty() { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); client.import_verified_blocks(&IoChannel::disconnected()); client.flush_queue(); } @@ -41,7 +42,7 @@ fn returns_state_root_basic() { #[test] fn imports_good_block() { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); let good_block = get_good_dummy_block(); if let Err(_) = client.import_block(good_block) { panic!("error importing block being good by definition"); @@ -56,7 +57,7 @@ fn imports_good_block() { #[test] fn query_none_block() { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); let non_existant = client.block_header(BlockID::Number(188)); assert!(non_existant.is_none()); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 7262da9e8..cc841d7f4 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -23,6 +23,7 @@ use evm::Schedule; use engine::*; use ethereum; use devtools::*; +use miner::Miner; #[cfg(feature = "json-tests")] pub enum ChainEra { @@ -139,7 +140,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); let test_spec = get_test_spec(); let test_engine = &test_spec.engine; let state_root = test_spec.genesis_header().state_root; @@ -205,7 +206,7 @@ pub fn push_blocks_to_client(client: &Arc, timestamp_salt: u64, starting pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); for block in &blocks { if let Err(_) = client.import_block(block.clone()) { panic!("panic importing block which is well-formed"); diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 7f5d5e333..eb50ea5d1 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,12 +19,12 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; -use ethcore::client::{MiningBlockChainClient, Client, ClientConfig}; +use ethcore::client::{MiningBlockChainClient, BlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; use ethcore::ethereum; use ethcore::transaction::{Transaction, Action}; -use ethcore::miner::{MinerService, ExternalMiner}; +use ethcore::miner::{MinerService, ExternalMiner, Miner}; use devtools::RandomTempPath; use util::io::IoChannel; use util::hash::Address; @@ -195,7 +195,7 @@ fn chain_harness(chain: BlockChain, mut cb: F) -> U assert!(spec.is_state_root_valid()); let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), spec, dir.as_path(), IoChannel::disconnected()).unwrap(); + let client = Client::new(ClientConfig::default(), spec, dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); let sync_provider = sync_provider(); let miner_service = miner_service(); let account_provider = account_provider(); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index dc397d77d..e3e773c26 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -101,7 +101,7 @@ use io::SyncIo; use time; use super::SyncConfig; use blocks::BlockCollection; -use ethcore::miner::{AccountDetails, TransactionImportResult}; +use ethcore::miner::{AccountDetails, TransactionImportResult, MinerService}; known_heap_size!(0, PeerInfo); @@ -1297,6 +1297,7 @@ mod tests { use ethcore::header::*; use ethcore::client::*; use ethcore::spec::Spec; + use ethcore::miner::MinerService; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { let mut header = Header::new(); @@ -1702,8 +1703,8 @@ mod tests { let mut queue = VecDeque::new(); let mut io = TestIo::new(&mut client, &mut queue, None); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); - assert_eq!(sync.miner.status().transactions_in_future_queue, 0); - assert_eq!(sync.miner.status().transactions_in_pending_queue, 1); + assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); + assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 1); } // We need to update nonce status (because we say that the block has been imported) for h in &[good_blocks[0]] { @@ -1718,7 +1719,7 @@ mod tests { } // then - let status = sync.miner.status(); + let status = client.miner.status(); assert_eq!(status.transactions_in_pending_queue, 1); assert_eq!(status.transactions_in_future_queue, 0); } @@ -1740,12 +1741,12 @@ mod tests { // when sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); - assert_eq!(sync.miner.status().transactions_in_future_queue, 0); - assert_eq!(sync.miner.status().transactions_in_pending_queue, 0); + assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); + assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 0); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks); // then - let status = sync.miner.status(); + let status = io.chain.miner.status(); assert_eq!(status.transactions_in_pending_queue, 0); assert_eq!(status.transactions_in_future_queue, 0); } diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 463771ffe..09e83e358 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{MiningClient, BlockID, EachBlockWith}; +use ethcore::client::{BlockChainClient, BlockID, EachBlockWith}; use chain::{SyncState}; use super::helpers::*; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 7cde0b54c..9ca0065ee 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{TestBlockChainClient, BlockChainClient}; +use ethcore::client::{TestBlockChainClient, MiningBlockChainClient, BlockChainClient}; use ethcore::spec::Spec; use io::SyncIo; use chain::ChainSync; @@ -62,7 +62,7 @@ impl<'p> SyncIo for TestIo<'p> { Ok(()) } - fn chain(&self) -> &MiningClient { + fn chain(&self) -> &BlockChainClient { self.chain } } From cee31f9e8da4d51b1bbf3bac714f86fe7575cf82 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 03:19:20 +0200 Subject: [PATCH 77/88] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 995b765c2..230e7862f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: global: # GH_TOKEN - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= - - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethjson -p ethcore-dapps -p ethcore-signer" + - TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer" - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - KCOV_FEATURES="" - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests target/kcov" From db749dc564bda58f07c71879db34b76b2ad0a2b1 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 12:44:11 +0200 Subject: [PATCH 78/88] fix remaining tests & doctest --- ethcore/src/client/test_client.rs | 13 ++++++++++--- sync/src/chain.rs | 9 ++------- sync/src/lib.rs | 7 +++---- sync/src/tests/helpers.rs | 3 +-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fa91aab4a..83799c78f 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -28,7 +28,7 @@ use receipt::{Receipt, LocalizedReceipt}; use blockchain::extras::BlockReceipts; use error::{ImportResult}; use evm::Factory as EvmFactory; -use miner::Miner; +use miner::{Miner, MinerService}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock, LockedBlock}; @@ -488,10 +488,17 @@ impl BlockChainClient for TestBlockChainClient { } fn import_transactions(&self, transactions: Vec) -> Vec> { - unimplemented!(); + let nonces = self.nonces.read().unwrap(); + let balances = self.balances.read().unwrap(); + let fetch_account = |a: &Address| AccountDetails { + nonce: nonces[a], + balance: balances[a], + }; + + self.miner.import_transactions(transactions, &fetch_account) } fn all_transactions(&self) -> Vec { - unimplemented!(); + self.miner.all_transactions() } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index e3e773c26..38d3a53f9 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -101,7 +101,6 @@ use io::SyncIo; use time; use super::SyncConfig; use blocks::BlockCollection; -use ethcore::miner::{AccountDetails, TransactionImportResult, MinerService}; known_heap_size!(0, PeerInfo); @@ -895,11 +894,6 @@ impl ChainSync { let tx: SignedTransaction = try!(r.val_at(i)); transactions.push(tx); } - let chain = io.chain(); - let fetch_account = |a: &Address| AccountDetails { - nonce: chain.latest_nonce(a), - balance: chain.latest_balance(a), - }; let _ = io.chain().import_transactions(transactions); Ok(()) } @@ -1296,7 +1290,6 @@ mod tests { use ethcore::views::BlockView; use ethcore::header::*; use ethcore::client::*; - use ethcore::spec::Spec; use ethcore::miner::MinerService; fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes { @@ -1702,6 +1695,7 @@ mod tests { { let mut queue = VecDeque::new(); let mut io = TestIo::new(&mut client, &mut queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &[], &good_blocks); sync.chain_new_blocks(&mut io, &[], &[], &[], &good_blocks); assert_eq!(io.chain.miner.status().transactions_in_future_queue, 0); assert_eq!(io.chain.miner.status().transactions_in_pending_queue, 1); @@ -1715,6 +1709,7 @@ mod tests { { let mut queue = VecDeque::new(); let mut io = TestIo::new(&mut client, &mut queue, None); + io.chain.miner.chain_new_blocks(io.chain, &[], &[], &good_blocks, &retracted_blocks); sync.chain_new_blocks(&mut io, &[], &[], &good_blocks, &retracted_blocks); } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 863ad6382..9f69bb7da 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -32,21 +32,20 @@ //! extern crate ethcore_util as util; //! extern crate ethcore; //! extern crate ethsync; -//! extern crate ethminer; //! use std::env; //! use std::sync::Arc; //! use util::network::{NetworkService, NetworkConfiguration}; //! use ethcore::client::{Client, ClientConfig}; //! use ethsync::{EthSync, SyncConfig}; -//! use ethminer::Miner; //! use ethcore::ethereum; +//! use ethcore::miner::Miner; //! //! fn main() { //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); -//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); +//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, Arc::new(Miner::default()), service.io().channel()).unwrap(); //! let miner = Miner::new(false, ethereum::new_frontier()); -//! EthSync::register(&mut service, SyncConfig::default(), client, miner); +//! EthSync::register(&mut service, SyncConfig::default(), client); //! } //! ``` diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 9ca0065ee..a9163b52e 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{TestBlockChainClient, MiningBlockChainClient, BlockChainClient}; -use ethcore::spec::Spec; +use ethcore::client::{TestBlockChainClient, BlockChainClient}; use io::SyncIo; use chain::ChainSync; use ::SyncConfig; From 985d412c483bf993b76b22b5628a7169f62c4e76 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 13:03:26 +0200 Subject: [PATCH 79/88] fix merges again --- rpc/src/v1/tests/eth.rs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 8cfc13191..4dc22df56 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,12 +19,8 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; -<<<<<<< HEAD use ethcore::client::{MiningBlockChainClient, BlockChainClient, Client, ClientConfig}; -use ethcore::spec::Genesis; -======= use ethcore::ids::BlockID; -use ethcore::client::{Client, BlockChainClient, ClientConfig}; use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; @@ -73,7 +69,7 @@ fn make_spec(chain: &BlockChain) -> Spec { } struct EthTester { - _client: Arc, + client: Arc, _miner: Arc, accounts: Arc, handler: IoHandler, @@ -101,10 +97,10 @@ impl EthTester { where F: Fn() -> Spec { let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), spec_provider(), dir.as_path(), IoChannel::disconnected()).unwrap(); - let sync_provider = sync_provider(); let account_provider = account_provider(); let miner_service = miner_service(spec_provider(), account_provider.clone()); + let client = Client::new(ClientConfig::default(), spec_provider(), dir.as_path(), miner_service.clone(), IoChannel::disconnected()).unwrap(); + let sync_provider = sync_provider(); let external_miner = Arc::new(ExternalMiner::default()); let eth_client = EthClient::new( @@ -347,25 +343,10 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { let (req, res) = by_hash(hash, count, &mut id); assert_eq!(tester.handler.handle_request(&req), Some(res)); -<<<<<<< HEAD - let dir = RandomTempPath::new(); - let client = Client::new(ClientConfig::default(), spec, dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); - let sync_provider = sync_provider(); - let miner_service = miner_service(); - let account_provider = account_provider(); - let external_miner = Arc::new(ExternalMiner::default()); - - for b in &chain.blocks_rlp() { - if Block::is_good(&b) { - let _ = client.import_block(b.clone()); - client.flush_queue(); - client.import_verified_blocks(&IoChannel::disconnected()); -======= // uncles can share block numbers, so skip them. if tester.client.block_hash(BlockID::Number(number)) == Some(hash) { let (req, res) = by_number(number, count, &mut id); assert_eq!(tester.handler.handle_request(&req), Some(res)); ->>>>>>> master } } } From ae572cb8f5be2b52ec3b5839605de6158637ab0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 1 Jun 2016 13:25:20 +0200 Subject: [PATCH 80/88] Using ordered hashmap to keep the order of dapps on home screen --- dapps/src/endpoint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs index 60708f549..28ca6ea11 100644 --- a/dapps/src/endpoint.rs +++ b/dapps/src/endpoint.rs @@ -21,7 +21,7 @@ use hyper::{header, server, Decoder, Encoder, Next}; use hyper::net::HttpStream; use std::io::Write; -use std::collections::HashMap; +use std::collections::BTreeMap; #[derive(Debug, PartialEq, Default, Clone)] pub struct EndpointPath { @@ -45,7 +45,7 @@ pub trait Endpoint : Send + Sync { fn to_handler(&self, path: EndpointPath) -> Box>; } -pub type Endpoints = HashMap>; +pub type Endpoints = BTreeMap>; pub type Handler = server::Handler; pub struct ContentHandler { From 1ef4db82e80bf6f7ed2459b8ce1036922c6370af Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 14:50:06 +0200 Subject: [PATCH 81/88] doctest fixes --- ethcore/src/client/mod.rs | 2 +- ethcore/src/miner/mod.rs | 3 +-- ethcore/src/miner/transaction_queue.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 209a9f6e2..3f64cb620 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -46,7 +46,7 @@ use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use trace::LocalizedTrace; use evm::Factory as EvmFactory; -use miner::{TransactionImportResult, AccountDetails}; +use miner::{TransactionImportResult}; use error::Error as EthError; /// Blockchain database client. Owns and manages a blockchain and a block queue. diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 0159d7fd6..60b680f7a 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -28,8 +28,7 @@ //! extern crate ethcore; //! use std::env; //! use util::network::{NetworkService, NetworkConfiguration}; -//! use client::{Client, ClientConfig}; -//! use ethereum; +//! use ethcore::client::{Client, ClientConfig}; //! use ethcore::miner::{Miner, MinerService}; //! //! fn main() { diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index bf1512bde..8f34d78d1 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -26,13 +26,12 @@ //! ```rust //! extern crate ethcore_util as util; //! extern crate ethcore; -//! extern crate ethminer; //! extern crate rustc_serialize; //! //! use util::crypto::KeyPair; //! use util::hash::Address; //! use util::numbers::{Uint, U256}; -//! use ethminer::{TransactionQueue, AccountDetails, TransactionOrigin}; +//! use ethcore::miner::{TransactionQueue, AccountDetails, TransactionOrigin}; //! use ethcore::transaction::*; //! use rustc_serialize::hex::FromHex; //! From 99e26b8480a2678954daa69852aa966d33f8e498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 1 Jun 2016 19:37:34 +0200 Subject: [PATCH 82/88] Simple signing queue, confirmation APIs exposed in signer WebSockets. (#1182) * Splitting methods requiring signing into separate trait * Single place where RPC apis are created. * Separating eth_filter * Separating eth_signing * Stubs for Personal Signer methods * Test for EthSigningQueueClient * TransactionConfirmation API * Exposing PersonalSigner API * Defining ApiSets dependent on context * Removing types * Fixing default impl * Fixing un-mocked tests * Update signing_queue.rs [ci skip] * Removing unused import [ci skip] --- Cargo.lock | 5 - dapps/src/lib.rs | 13 +- parity/dapps.rs | 24 +- parity/main.rs | 27 +-- parity/rpc.rs | 79 ++----- parity/rpc_apis.rs | 168 ++++++++++++++ parity/signer.rs | 18 +- rpc/src/lib.rs | 19 +- rpc/src/v1/helpers/mod.rs | 2 + rpc/src/v1/helpers/signing_queue.rs | 108 +++++++++ rpc/src/v1/impls/eth.rs | 246 ++------------------- rpc/src/v1/impls/eth_filter.rs | 214 ++++++++++++++++++ rpc/src/v1/impls/eth_signing.rs | 111 ++++++++++ rpc/src/v1/impls/mod.rs | 10 +- rpc/src/v1/impls/personal.rs | 2 +- rpc/src/v1/impls/personal_signer.rs | 93 ++++++++ rpc/src/v1/mod.rs | 3 +- rpc/src/v1/tests/eth.rs | 15 +- rpc/src/v1/tests/mocked/eth.rs | 5 +- rpc/src/v1/tests/mocked/eth_signing.rs | 75 +++++++ rpc/src/v1/tests/mocked/mod.rs | 2 + rpc/src/v1/tests/mocked/personal.rs | 2 +- rpc/src/v1/tests/mocked/personal_signer.rs | 169 ++++++++++++++ rpc/src/v1/traits/eth.rs | 25 ++- rpc/src/v1/traits/mod.rs | 6 +- rpc/src/v1/traits/personal.rs | 23 ++ rpc/src/v1/types/mod.rs.in | 2 +- rpc/src/v1/types/transaction_request.rs | 41 +++- signer/Cargo.toml | 8 - signer/build.rs | 27 --- signer/src/lib.rs | 8 - signer/src/signing_queue.rs | 74 ------- signer/src/types/mod.rs | 23 -- signer/src/types/mod.rs.in | 25 --- signer/src/ws_server/mod.rs | 12 +- 35 files changed, 1140 insertions(+), 544 deletions(-) create mode 100644 parity/rpc_apis.rs create mode 100644 rpc/src/v1/helpers/signing_queue.rs create mode 100644 rpc/src/v1/impls/eth_filter.rs create mode 100644 rpc/src/v1/impls/eth_signing.rs create mode 100644 rpc/src/v1/impls/personal_signer.rs create mode 100644 rpc/src/v1/tests/mocked/eth_signing.rs create mode 100644 rpc/src/v1/tests/mocked/personal_signer.rs delete mode 100644 signer/src/signing_queue.rs delete mode 100644 signer/src/types/mod.rs delete mode 100644 signer/src/types/mod.rs.in diff --git a/Cargo.lock b/Cargo.lock index cc2a8ef8c..c81020f66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,12 +358,7 @@ dependencies = [ "ethcore-util 1.2.0", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 27c215108..231e7b080 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -52,6 +52,7 @@ extern crate serde_json; extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate parity_dapps; +extern crate ethcore_rpc; mod endpoint; mod apps; @@ -66,6 +67,7 @@ use std::net::SocketAddr; use std::collections::HashMap; use jsonrpc_core::{IoHandler, IoDelegate}; use router::auth::{Authorization, NoAuth, HttpBasicAuth}; +use ethcore_rpc::Extendable; static DAPPS_DOMAIN : &'static str = ".parity"; @@ -74,6 +76,12 @@ pub struct ServerBuilder { handler: Arc, } +impl Extendable for ServerBuilder { + fn add_delegate(&self, delegate: IoDelegate) { + self.handler.add_delegate(delegate); + } +} + impl ServerBuilder { /// Construct new dapps server pub fn new() -> Self { @@ -82,11 +90,6 @@ impl ServerBuilder { } } - /// Add io delegate. - pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { - self.handler.add_delegate(delegate); - } - /// Asynchronously start server with no authentication, /// returns result with `Server` handle on success or an error. pub fn start_unsecure_http(&self, addr: &SocketAddr) -> Result { diff --git a/parity/dapps.rs b/parity/dapps.rs index 986e3dd07..91742d9e3 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -17,14 +17,9 @@ use std::sync::Arc; use std::str::FromStr; use std::net::SocketAddr; -use ethcore::client::Client; -use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; -use util::RotatingLogger; use util::panics::PanicHandler; -use util::keys::store::AccountService; -use util::network_settings::NetworkSettings; use die::*; +use rpc_apis; #[cfg(feature = "dapps")] pub use ethcore_dapps::Server as WebappServer; @@ -41,13 +36,7 @@ pub struct Configuration { pub struct Dependencies { pub panic_handler: Arc, - pub client: Arc, - pub sync: Arc, - pub secret_store: Arc, - pub miner: Arc, - pub external_miner: Arc, - pub logger: Arc, - pub settings: Arc, + pub apis: Arc, } pub fn new(configuration: Configuration, deps: Dependencies) -> Option { @@ -92,17 +81,10 @@ pub fn setup_dapps_server( url: &SocketAddr, auth: Option<(String, String)> ) -> WebappServer { - use ethcore_rpc::v1::*; use ethcore_dapps as dapps; let server = dapps::ServerBuilder::new(); - server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(NetClient::new(&deps.sync).to_delegate()); - server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); - server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); - server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate()); - server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()); - + let server = rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::UnsafeContext); let start_result = match auth { None => { server.start_unsecure_http(url) diff --git a/parity/main.rs b/parity/main.rs index 7f16d28a5..cae6aa614 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -67,6 +67,7 @@ mod cli; mod configuration; mod migration; mod signer; +mod rpc_apis; use std::io::{Write, Read, BufReader, BufRead}; use std::ops::Deref; @@ -195,8 +196,9 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) // Sync let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); - let dependencies = Arc::new(rpc::Dependencies { - panic_handler: panic_handler.clone(), + let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies { + signer_enabled: conf.args.flag_signer, + signer_queue: Arc::new(rpc_apis::ConfirmationsQueue::default()), client: client.clone(), sync: sync.clone(), secret_store: account_service.clone(), @@ -206,6 +208,11 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) settings: network_settings.clone(), }); + let dependencies = rpc::Dependencies { + panic_handler: panic_handler.clone(), + apis: deps_for_rpc_apis.clone(), + }; + // Setup http rpc let rpc_server = rpc::new_http(rpc::HttpConfiguration { enabled: network_settings.rpc_enabled, @@ -227,26 +234,16 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) pass: conf.args.flag_dapps_pass.clone(), }, dapps::Dependencies { panic_handler: panic_handler.clone(), - client: client.clone(), - sync: sync.clone(), - secret_store: account_service.clone(), - miner: miner.clone(), - external_miner: external_miner.clone(), - logger: logger.clone(), - settings: network_settings.clone(), + apis: deps_for_rpc_apis.clone(), }); // Set up a signer let signer_server = signer::start(signer::Configuration { - enabled: conf.args.flag_signer, + enabled: deps_for_rpc_apis.signer_enabled, port: conf.args.flag_signer_port, }, signer::Dependencies { panic_handler: panic_handler.clone(), - client: client.clone(), - sync: sync.clone(), - secret_store: account_service.clone(), - miner: miner.clone(), - external_miner: external_miner.clone(), + apis: deps_for_rpc_apis.clone(), }); // Register IO handler diff --git a/parity/rpc.rs b/parity/rpc.rs index 60766263b..66f504408 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -15,19 +15,13 @@ // along with Parity. If not, see . -use std::collections::BTreeMap; use std::str::FromStr; use std::sync::Arc; use std::net::SocketAddr; -use ethcore::client::Client; -use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; -use util::RotatingLogger; use util::panics::PanicHandler; -use util::keys::store::AccountService; -use util::network_settings::NetworkSettings; use die::*; use jsonipc; +use rpc_apis; #[cfg(feature = "rpc")] pub use ethcore_rpc::Server as RpcServer; @@ -52,16 +46,10 @@ pub struct IpcConfiguration { pub struct Dependencies { pub panic_handler: Arc, - pub client: Arc, - pub sync: Arc, - pub secret_store: Arc, - pub miner: Arc, - pub external_miner: Arc, - pub logger: Arc, - pub settings: Arc, + pub apis: Arc, } -pub fn new_http(conf: HttpConfiguration, deps: &Arc) -> Option { +pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Option { if !conf.enabled { return None; } @@ -78,58 +66,23 @@ pub fn new_http(conf: HttpConfiguration, deps: &Arc) -> Option) -> Option { +pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Option { if !conf.enabled { return None; } let apis = conf.apis.split(',').collect(); Some(setup_ipc_rpc_server(deps, &conf.socket_addr, apis)) } -fn setup_rpc_server(apis: Vec<&str>, deps: &Arc) -> Server { - use ethcore_rpc::v1::*; - +fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server { + let apis = rpc_apis::from_str(apis); let server = Server::new(); - let mut modules = BTreeMap::new(); - for api in apis.into_iter() { - match api { - "web3" => { - modules.insert("web3".to_owned(), "1.0".to_owned()); - server.add_delegate(Web3Client::new().to_delegate()); - }, - "net" => { - modules.insert("net".to_owned(), "1.0".to_owned()); - server.add_delegate(NetClient::new(&deps.sync).to_delegate()); - }, - "eth" => { - modules.insert("eth".to_owned(), "1.0".to_owned()); - server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); - server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); - }, - "personal" => { - modules.insert("personal".to_owned(), "1.0".to_owned()); - server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate()) - }, - "ethcore" => { - modules.insert("ethcore".to_owned(), "1.0".to_owned()); - server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) - }, - "traces" => { - modules.insert("traces".to_owned(), "1.0".to_owned()); - server.add_delegate(TracesClient::new(&deps.client).to_delegate()) - }, - _ => { - die!("{}: Invalid API name to be enabled.", api); - }, - } - } - server.add_delegate(RpcClient::new(modules).to_delegate()); - server + rpc_apis::setup_rpc(server, deps.apis.clone(), rpc_apis::ApiSet::List(apis)) } #[cfg(not(feature = "rpc"))] pub fn setup_http_rpc_server( - _deps: Dependencies, + _deps: &Dependencies, _url: &SocketAddr, - _cors_domain: Option, + _cors_domain: Vec, _apis: Vec<&str>, ) -> ! { die!("Your Parity version has been compiled without JSON-RPC support.") @@ -137,27 +90,31 @@ pub fn setup_http_rpc_server( #[cfg(feature = "rpc")] pub fn setup_http_rpc_server( - dependencies: &Arc, + dependencies: &Dependencies, url: &SocketAddr, cors_domains: Vec, apis: Vec<&str>, ) -> RpcServer { let server = setup_rpc_server(apis, dependencies); let start_result = server.start_http(url, cors_domains); - let deps = dependencies.clone(); + let ph = dependencies.panic_handler.clone(); match start_result { Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), Err(e) => die!("RPC: {:?}", e), Ok(server) => { server.set_panic_handler(move || { - deps.panic_handler.notify_all("Panic in RPC thread.".to_owned()); + ph.notify_all("Panic in RPC thread.".to_owned()); }); server }, } } - -pub fn setup_ipc_rpc_server(dependencies: &Arc, addr: &str, apis: Vec<&str>) -> jsonipc::Server { +#[cfg(not(feature = "rpc"))] +pub fn setup_ipc_rpc_server(_dependencies: &Dependencies, _addr: &str, _apis: Vec<&str>) -> ! { + die!("Your Parity version has been compiled without JSON-RPC support.") +} +#[cfg(feature = "rpc")] +pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: Vec<&str>) -> jsonipc::Server { let server = setup_rpc_server(apis, dependencies); match server.start_ipc(addr) { Err(jsonipc::Error::Io(io_error)) => die_with_io_error("RPC", io_error), diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs new file mode 100644 index 000000000..c73a70fee --- /dev/null +++ b/parity/rpc_apis.rs @@ -0,0 +1,168 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::BTreeMap; +use std::str::FromStr; +use std::sync::Arc; + +use die::*; +use ethsync::EthSync; +use ethminer::{Miner, ExternalMiner}; +use ethcore::client::Client; +use util::RotatingLogger; +use util::keys::store::AccountService; +use util::network_settings::NetworkSettings; + +#[cfg(feature="rpc")] +pub use ethcore_rpc::ConfirmationsQueue; +#[cfg(not(feature="rpc"))] +#[derive(Default)] +pub struct ConfirmationsQueue; + +#[cfg(feature="rpc")] +use ethcore_rpc::Extendable; + +pub enum Api { + Web3, + Net, + Eth, + Personal, + Ethcore, + Traces, + Rpc, +} + +pub enum ApiError { + UnknownApi(String) +} + +pub enum ApiSet { + SafeContext, + UnsafeContext, + List(Vec), +} + +impl FromStr for Api { + type Err = ApiError; + + fn from_str(s: &str) -> Result { + use self::Api::*; + + match s { + "web3" => Ok(Web3), + "net" => Ok(Net), + "eth" => Ok(Eth), + "personal" => Ok(Personal), + "ethcore" => Ok(Ethcore), + "traces" => Ok(Traces), + "rpc" => Ok(Rpc), + e => Err(ApiError::UnknownApi(e.into())), + } + } +} + +pub struct Dependencies { + pub signer_enabled: bool, + pub signer_queue: Arc, + pub client: Arc, + pub sync: Arc, + pub secret_store: Arc, + pub miner: Arc, + pub external_miner: Arc, + pub logger: Arc, + pub settings: Arc, +} + +fn to_modules(apis: &[Api]) -> BTreeMap { + let mut modules = BTreeMap::new(); + for api in apis { + let (name, version) = match *api { + Api::Web3 => ("web3", "1.0"), + Api::Net => ("net", "1.0"), + Api::Eth => ("eth", "1.0"), + Api::Personal => ("personal", "1.0"), + Api::Ethcore => ("ethcore", "1.0"), + Api::Traces => ("traces", "1.0"), + Api::Rpc => ("rpc", "1.0"), + }; + modules.insert(name.into(), version.into()); + } + modules +} + +pub fn from_str(apis: Vec<&str>) -> Vec { + apis.into_iter() + .map(Api::from_str) + .collect::, ApiError>>() + .unwrap_or_else(|e| match e { + ApiError::UnknownApi(s) => die!("Unknown RPC API specified: {}", s), + }) +} + +fn list_apis(apis: ApiSet, signer_enabled: bool) -> Vec { + match apis { + ApiSet::List(apis) => apis, + ApiSet::UnsafeContext if signer_enabled => { + vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc] + } + _ => { + vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Ethcore, Api::Traces, Api::Rpc] + } + } +} + +pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet) -> T { + use ethcore_rpc::v1::*; + + let apis = list_apis(apis, deps.signer_enabled); + for api in &apis { + match *api { + Api::Web3 => { + server.add_delegate(Web3Client::new().to_delegate()); + }, + Api::Net => { + server.add_delegate(NetClient::new(&deps.sync).to_delegate()); + }, + Api::Eth => { + server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); + + if deps.signer_enabled { + server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue).to_delegate()); + } else { + server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate()); + } + }, + Api::Personal => { + server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate()); + if deps.signer_enabled { + server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate()); + } + }, + Api::Ethcore => { + server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) + }, + Api::Traces => { + server.add_delegate(TracesClient::new(&deps.client).to_delegate()) + }, + Api::Rpc => { + let modules = to_modules(&apis); + server.add_delegate(RpcClient::new(modules).to_delegate()); + } + } + } + server +} diff --git a/parity/signer.rs b/parity/signer.rs index 5e3339bcc..d549b89cb 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -15,12 +15,9 @@ // along with Parity. If not, see . use std::sync::Arc; -use ethcore::client::Client; -use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; -use util::keys::store::AccountService; use util::panics::{PanicHandler, ForwardPanic}; use die::*; +use rpc_apis; #[cfg(feature = "ethcore-signer")] use ethcore_signer as signer; @@ -36,11 +33,7 @@ pub struct Configuration { pub struct Dependencies { pub panic_handler: Arc, - pub client: Arc, - pub sync: Arc, - pub secret_store: Arc, - pub miner: Arc, - pub external_miner: Arc, + pub apis: Arc, } pub fn start(conf: Configuration, deps: Dependencies) -> Option { @@ -58,13 +51,8 @@ fn do_start(conf: Configuration, deps: Dependencies) -> SignerServer { }); let start_result = { - use ethcore_rpc::v1::*; let server = signer::ServerBuilder::new(); - server.add_delegate(Web3Client::new().to_delegate()); - server.add_delegate(NetClient::new(&deps.sync).to_delegate()); - server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate()); - server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate()); - server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate()); + let server = rpc_apis::setup_rpc(server, deps.apis, rpc_apis::ApiSet::SafeContext); server.start(addr) }; diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 24d58819c..607bcf4bd 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -44,12 +44,26 @@ use self::jsonrpc_core::{IoHandler, IoDelegate}; pub use jsonrpc_http_server::{Server, RpcServerError}; pub mod v1; +pub use v1::{SigningQueue, ConfirmationsQueue}; + +/// An object that can be extended with `IoDelegates` +pub trait Extendable { + /// Add `Delegate` to this object. + fn add_delegate(&self, delegate: IoDelegate); +} /// Http server. pub struct RpcServer { handler: Arc, } +impl Extendable for RpcServer { + /// Add io delegate. + fn add_delegate(&self, delegate: IoDelegate) { + self.handler.add_delegate(delegate); + } +} + impl RpcServer { /// Construct new http server object. pub fn new() -> RpcServer { @@ -58,11 +72,6 @@ impl RpcServer { } } - /// Add io delegate. - pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { - self.handler.add_delegate(delegate); - } - /// Start http server asynchronously and returns result with `Server` handle on success or an error. pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec) -> Result { let cors_domains = cors_domains.into_iter() diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index b1a5c05ba..2acf98bf2 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -16,6 +16,8 @@ mod poll_manager; mod poll_filter; +mod signing_queue; pub use self::poll_manager::PollManager; pub use self::poll_filter::PollFilter; +pub use self::signing_queue::{ConfirmationsQueue, SigningQueue}; diff --git a/rpc/src/v1/helpers/signing_queue.rs b/rpc/src/v1/helpers/signing_queue.rs new file mode 100644 index 000000000..eee4328ee --- /dev/null +++ b/rpc/src/v1/helpers/signing_queue.rs @@ -0,0 +1,108 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Mutex; +use std::collections::HashMap; +use v1::types::{TransactionRequest, TransactionConfirmation}; +use util::U256; + +/// A queue of transactions awaiting to be confirmed and signed. +pub trait SigningQueue: Send + Sync { + /// Add new request to the queue. + fn add_request(&self, transaction: TransactionRequest) -> U256; + + /// Remove request from the queue. + fn remove_request(&self, id: U256) -> Option; + + /// Return copy of all the requests in the queue. + fn requests(&self) -> Vec; +} + +/// Queue for all unconfirmed transactions. +pub struct ConfirmationsQueue { + id: Mutex, + queue: Mutex>, +} + +impl Default for ConfirmationsQueue { + fn default() -> Self { + ConfirmationsQueue { + id: Mutex::new(U256::from(0)), + queue: Mutex::new(HashMap::new()), + } + } +} + +impl SigningQueue for ConfirmationsQueue { + fn add_request(&self, transaction: TransactionRequest) -> U256 { + // Increment id + let id = { + let mut last_id = self.id.lock().unwrap(); + *last_id = *last_id + U256::from(1); + *last_id + }; + let mut queue = self.queue.lock().unwrap(); + queue.insert(id, TransactionConfirmation { + id: id, + transaction: transaction, + }); + id + } + + fn remove_request(&self, id: U256) -> Option { + self.queue.lock().unwrap().remove(&id) + } + + fn requests(&self) -> Vec { + let queue = self.queue.lock().unwrap(); + queue.values().cloned().collect() + } +} + + +#[cfg(test)] +mod test { + use util::hash::Address; + use util::numbers::U256; + use v1::types::TransactionRequest; + use super::*; + + #[test] + fn should_work_for_hashset() { + // given + let queue = ConfirmationsQueue::default(); + + let request = TransactionRequest { + from: Address::from(1), + to: Some(Address::from(2)), + gas_price: None, + gas: None, + value: Some(U256::from(10_000_000)), + data: None, + nonce: None, + }; + + // when + queue.add_request(request.clone()); + let all = queue.requests(); + + // then + assert_eq!(all.len(), 1); + let el = all.get(0).unwrap(); + assert_eq!(el.id, U256::from(1)); + assert_eq!(el.transaction, request); + } +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a57fc333c..e0225c7e9 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -18,7 +18,6 @@ extern crate ethash; -use std::collections::HashSet; use std::sync::{Arc, Weak, Mutex}; use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; @@ -36,10 +35,9 @@ use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Act use ethcore::log_entry::LogEntry; use ethcore::filter::Filter as EthcoreFilter; use self::ethash::SeedHashCompute; -use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; -use v1::helpers::{PollFilter, PollManager}; -use v1::impls::{dispatch_transaction, sign_and_dispatch}; +use v1::traits::Eth; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; +use v1::impls::dispatch_transaction; use serde; /// Eth rpc implementation. @@ -170,6 +168,25 @@ impl EthClient where } } +pub fn pending_logs(miner: &M, filter: &EthcoreFilter) -> Vec where M: MinerService { + let receipts = miner.pending_receipts(); + + let pending_logs = receipts.into_iter() + .flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::>()) + .collect::>(); + + let result = pending_logs.into_iter() + .filter(|pair| filter.matches(&pair.1)) + .map(|pair| { + let mut log = Log::from(pair.1); + log.transaction_hash = Some(pair.0); + log + }) + .collect(); + + result +} + const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. fn params_len(params: &Params) -> usize { @@ -193,25 +210,6 @@ fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNum } } -fn pending_logs(miner: &M, filter: &EthcoreFilter) -> Vec where M: MinerService { - let receipts = miner.pending_receipts(); - - let pending_logs = receipts.into_iter() - .flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::>()) - .collect::>(); - - let result = pending_logs.into_iter() - .filter(|pair| filter.matches(&pair.1)) - .map(|pair| { - let mut log = Log::from(pair.1); - log.transaction_hash = Some(pair.0); - log - }) - .collect(); - - result -} - // must be in range [-32099, -32000] const UNSUPPORTED_REQUEST_CODE: i64 = -32000; @@ -496,23 +494,6 @@ impl Eth for EthClient where }) } - fn sign(&self, params: Params) -> Result { - from_params::<(Address, H256)>(params).and_then(|(addr, msg)| { - to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero())) - }) - } - - fn send_transaction(&self, params: Params) -> Result { - from_params::<(TransactionRequest, )>(params) - .and_then(|(request, )| { - let accounts = take_weak!(self.accounts); - match accounts.account_secret(&request.from) { - Ok(secret) => sign_and_dispatch(&self.client, &self.miner, request, secret), - Err(_) => to_value(&H256::zero()) - } - }) - } - fn send_raw_transaction(&self, params: Params) -> Result { from_params::<(Bytes, )>(params) .and_then(|(raw_transaction, )| { @@ -563,186 +544,3 @@ impl Eth for EthClient where rpc_unimplemented!() } } - -/// Eth filter rpc implementation. -pub struct EthFilterClient where - C: BlockChainClient, - M: MinerService { - - client: Weak, - miner: Weak, - polls: Mutex>, -} - -impl EthFilterClient where - C: BlockChainClient, - M: MinerService { - - /// Creates new Eth filter client. - pub fn new(client: &Arc, miner: &Arc) -> Self { - EthFilterClient { - client: Arc::downgrade(client), - miner: Arc::downgrade(miner), - polls: Mutex::new(PollManager::new()), - } - } -} - -impl EthFilter for EthFilterClient where - C: BlockChainClient + 'static, - M: MinerService + 'static { - - fn new_filter(&self, params: Params) -> Result { - from_params::<(Filter,)>(params) - .and_then(|(filter,)| { - let mut polls = self.polls.lock().unwrap(); - let block_number = take_weak!(self.client).chain_info().best_block_number; - let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter)); - to_value(&U256::from(id)) - }) - } - - fn new_block_filter(&self, params: Params) -> Result { - match params { - Params::None => { - let mut polls = self.polls.lock().unwrap(); - let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); - to_value(&U256::from(id)) - }, - _ => Err(Error::invalid_params()) - } - } - - fn new_pending_transaction_filter(&self, params: Params) -> Result { - match params { - Params::None => { - let mut polls = self.polls.lock().unwrap(); - let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); - let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); - - to_value(&U256::from(id)) - }, - _ => Err(Error::invalid_params()) - } - } - - fn filter_changes(&self, params: Params) -> Result { - let client = take_weak!(self.client); - from_params::<(Index,)>(params) - .and_then(|(index,)| { - let mut polls = self.polls.lock().unwrap(); - match polls.poll_mut(&index.value()) { - None => Ok(Value::Array(vec![] as Vec)), - Some(filter) => match *filter { - PollFilter::Block(ref mut block_number) => { - // + 1, cause we want to return hashes including current block hash. - let current_number = client.chain_info().best_block_number + 1; - let hashes = (*block_number..current_number).into_iter() - .map(BlockID::Number) - .filter_map(|id| client.block_hash(id)) - .collect::>(); - - *block_number = current_number; - - to_value(&hashes) - }, - PollFilter::PendingTransaction(ref mut previous_hashes) => { - // get hashes of pending transactions - let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); - - let new_hashes = - { - let previous_hashes_set = previous_hashes.iter().collect::>(); - - // find all new hashes - current_hashes - .iter() - .filter(|hash| !previous_hashes_set.contains(hash)) - .cloned() - .collect::>() - }; - - // save all hashes of pending transactions - *previous_hashes = current_hashes; - - // return new hashes - to_value(&new_hashes) - }, - PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => { - // retrive the current block number - let current_number = client.chain_info().best_block_number; - - // check if we need to check pending hashes - let include_pending = filter.to_block == Some(BlockNumber::Pending); - - // build appropriate filter - let mut filter: EthcoreFilter = filter.clone().into(); - filter.from_block = BlockID::Number(*block_number); - filter.to_block = BlockID::Latest; - - // retrieve logs in range from_block..min(BlockID::Latest..to_block) - let mut logs = client.logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - - // additionally retrieve pending logs - if include_pending { - let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter); - - // remove logs about which client was already notified about - let new_pending_logs: Vec<_> = pending_logs.iter() - .filter(|p| !previous_logs.contains(p)) - .cloned() - .collect(); - - // save all logs retrieved by client - *previous_logs = pending_logs.into_iter().collect(); - - // append logs array with new pending logs - logs.extend(new_pending_logs); - } - - // save current block number as next from block number - *block_number = current_number; - - to_value(&logs) - } - } - } - }) - } - - fn filter_logs(&self, params: Params) -> Result { - from_params::<(Index,)>(params) - .and_then(|(index,)| { - let mut polls = self.polls.lock().unwrap(); - match polls.poll(&index.value()) { - Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => { - let include_pending = filter.to_block == Some(BlockNumber::Pending); - let filter: EthcoreFilter = filter.clone().into(); - let mut logs = take_weak!(self.client).logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - - if include_pending { - logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter)); - } - - to_value(&logs) - }, - // just empty array - _ => Ok(Value::Array(vec![] as Vec)), - } - }) - } - - fn uninstall_filter(&self, params: Params) -> Result { - from_params::<(Index,)>(params) - .and_then(|(index,)| { - self.polls.lock().unwrap().remove_poll(&index.value()); - to_value(&true) - }) - } -} diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs new file mode 100644 index 000000000..c6aecdca2 --- /dev/null +++ b/rpc/src/v1/impls/eth_filter.rs @@ -0,0 +1,214 @@ +// 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 . + +//! Eth Filter RPC implementation + +use std::ops::Deref; +use std::sync::{Arc, Weak, Mutex}; +use std::collections::HashSet; +use jsonrpc_core::*; +use util::numbers::*; +use ethminer::MinerService; +use ethcore::filter::Filter as EthcoreFilter; +use ethcore::client::{BlockChainClient, BlockID}; +use v1::traits::EthFilter; +use v1::types::{BlockNumber, Index, Filter, Log}; +use v1::helpers::{PollFilter, PollManager}; +use v1::impls::eth::pending_logs; + + +/// Eth filter rpc implementation. +pub struct EthFilterClient where + C: BlockChainClient, + M: MinerService { + + client: Weak, + miner: Weak, + polls: Mutex>, +} + +impl EthFilterClient where + C: BlockChainClient, + M: MinerService { + + /// Creates new Eth filter client. + pub fn new(client: &Arc, miner: &Arc) -> Self { + EthFilterClient { + client: Arc::downgrade(client), + miner: Arc::downgrade(miner), + polls: Mutex::new(PollManager::new()), + } + } +} + +impl EthFilter for EthFilterClient where + C: BlockChainClient + 'static, + M: MinerService + 'static { + + fn new_filter(&self, params: Params) -> Result { + from_params::<(Filter,)>(params) + .and_then(|(filter,)| { + let mut polls = self.polls.lock().unwrap(); + let block_number = take_weak!(self.client).chain_info().best_block_number; + let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter)); + to_value(&U256::from(id)) + }) + } + + fn new_block_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } + } + + fn new_pending_transaction_filter(&self, params: Params) -> Result { + match params { + Params::None => { + let mut polls = self.polls.lock().unwrap(); + let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); + let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + + to_value(&U256::from(id)) + }, + _ => Err(Error::invalid_params()) + } + } + + fn filter_changes(&self, params: Params) -> Result { + let client = take_weak!(self.client); + from_params::<(Index,)>(params) + .and_then(|(index,)| { + let mut polls = self.polls.lock().unwrap(); + match polls.poll_mut(&index.value()) { + None => Ok(Value::Array(vec![] as Vec)), + Some(filter) => match *filter { + PollFilter::Block(ref mut block_number) => { + // + 1, cause we want to return hashes including current block hash. + let current_number = client.chain_info().best_block_number + 1; + let hashes = (*block_number..current_number).into_iter() + .map(BlockID::Number) + .filter_map(|id| client.block_hash(id)) + .collect::>(); + + *block_number = current_number; + + to_value(&hashes) + }, + PollFilter::PendingTransaction(ref mut previous_hashes) => { + // get hashes of pending transactions + let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); + + let new_hashes = + { + let previous_hashes_set = previous_hashes.iter().collect::>(); + + // find all new hashes + current_hashes + .iter() + .filter(|hash| !previous_hashes_set.contains(hash)) + .cloned() + .collect::>() + }; + + // save all hashes of pending transactions + *previous_hashes = current_hashes; + + // return new hashes + to_value(&new_hashes) + }, + PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => { + // retrive the current block number + let current_number = client.chain_info().best_block_number; + + // check if we need to check pending hashes + let include_pending = filter.to_block == Some(BlockNumber::Pending); + + // build appropriate filter + let mut filter: EthcoreFilter = filter.clone().into(); + filter.from_block = BlockID::Number(*block_number); + filter.to_block = BlockID::Latest; + + // retrieve logs in range from_block..min(BlockID::Latest..to_block) + let mut logs = client.logs(filter.clone()) + .into_iter() + .map(From::from) + .collect::>(); + + // additionally retrieve pending logs + if include_pending { + let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter); + + // remove logs about which client was already notified about + let new_pending_logs: Vec<_> = pending_logs.iter() + .filter(|p| !previous_logs.contains(p)) + .cloned() + .collect(); + + // save all logs retrieved by client + *previous_logs = pending_logs.into_iter().collect(); + + // append logs array with new pending logs + logs.extend(new_pending_logs); + } + + // save current block number as next from block number + *block_number = current_number; + + to_value(&logs) + } + } + } + }) + } + + fn filter_logs(&self, params: Params) -> Result { + from_params::<(Index,)>(params) + .and_then(|(index,)| { + let mut polls = self.polls.lock().unwrap(); + match polls.poll(&index.value()) { + Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => { + let include_pending = filter.to_block == Some(BlockNumber::Pending); + let filter: EthcoreFilter = filter.clone().into(); + let mut logs = take_weak!(self.client).logs(filter.clone()) + .into_iter() + .map(From::from) + .collect::>(); + + if include_pending { + logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter)); + } + + to_value(&logs) + }, + // just empty array + _ => Ok(Value::Array(vec![] as Vec)), + } + }) + } + + fn uninstall_filter(&self, params: Params) -> Result { + from_params::<(Index,)>(params) + .and_then(|(index,)| { + self.polls.lock().unwrap().remove_poll(&index.value()); + to_value(&true) + }) + } +} diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs new file mode 100644 index 000000000..04011902b --- /dev/null +++ b/rpc/src/v1/impls/eth_signing.rs @@ -0,0 +1,111 @@ +// 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 . + +//! Eth Signing RPC implementation. + +use std::sync::{Arc, Weak}; +use jsonrpc_core::*; +use ethminer::MinerService; +use ethcore::client::BlockChainClient; +use util::numbers::*; +use util::keys::store::AccountProvider; +use v1::helpers::{SigningQueue, ConfirmationsQueue}; +use v1::traits::EthSigning; +use v1::types::TransactionRequest; +use v1::impls::sign_and_dispatch; + + +/// Implementation of functions that require signing when no trusted signer is used. +pub struct EthSigningQueueClient { + queue: Weak, +} + +impl EthSigningQueueClient { + /// Creates a new signing queue client given shared signing queue. + pub fn new(queue: &Arc) -> Self { + EthSigningQueueClient { + queue: Arc::downgrade(queue), + } + } +} + +impl EthSigning for EthSigningQueueClient { + + fn sign(&self, _params: Params) -> Result { + // TODO [ToDr] Implement sign when rest of the signing queue is ready. + rpc_unimplemented!() + } + + fn send_transaction(&self, params: Params) -> Result { + from_params::<(TransactionRequest, )>(params) + .and_then(|(request, )| { + let queue = take_weak!(self.queue); + queue.add_request(request); + // TODO [ToDr] Block and wait for confirmation? + to_value(&H256::zero()) + }) + } +} + +/// Implementation of functions that require signing when no trusted signer is used. +pub struct EthSigningUnsafeClient where + C: BlockChainClient, + A: AccountProvider, + M: MinerService { + client: Weak, + accounts: Weak, + miner: Weak, +} + +impl EthSigningUnsafeClient where + C: BlockChainClient, + A: AccountProvider, + M: MinerService { + + /// Creates new EthClient. + pub fn new(client: &Arc, accounts: &Arc, miner: &Arc) + -> Self { + EthSigningUnsafeClient { + client: Arc::downgrade(client), + miner: Arc::downgrade(miner), + accounts: Arc::downgrade(accounts), + } + } +} + +impl EthSigning for EthSigningUnsafeClient where + C: BlockChainClient + 'static, + A: AccountProvider + 'static, + M: MinerService + 'static { + + fn sign(&self, params: Params) -> Result { + from_params::<(Address, H256)>(params).and_then(|(addr, msg)| { + to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero())) + }) + } + + fn send_transaction(&self, params: Params) -> Result { + from_params::<(TransactionRequest, )>(params) + .and_then(|(request, )| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&request.from) { + Ok(secret) => sign_and_dispatch(&self.client, &self.miner, request, secret), + Err(_) => to_value(&H256::zero()) + } + }) + } + +} diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 7ee8b8b8a..975a5fa77 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -31,16 +31,22 @@ macro_rules! rpc_unimplemented { mod web3; mod eth; +mod eth_filter; +mod eth_signing; mod net; mod personal; +mod personal_signer; mod ethcore; mod traces; mod rpc; pub use self::web3::Web3Client; -pub use self::eth::{EthClient, EthFilterClient}; +pub use self::eth::EthClient; +pub use self::eth_filter::EthFilterClient; +pub use self::eth_signing::{EthSigningUnsafeClient, EthSigningQueueClient}; pub use self::net::NetClient; pub use self::personal::PersonalClient; +pub use self::personal_signer::SignerClient; pub use self::ethcore::EthcoreClient; pub use self::traces::TracesClient; pub use self::rpc::RpcClient; @@ -92,4 +98,4 @@ fn sign_and_dispatch(client: &Weak, miner: &Weak, request: Transacti trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); dispatch_transaction(&*client, &*miner, signed_transaction) -} \ No newline at end of file +} diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 19e902996..30d541772 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -20,7 +20,7 @@ use jsonrpc_core::*; use v1::traits::Personal; use v1::types::TransactionRequest; use v1::impls::sign_and_dispatch; -use util::keys::store::*; +use util::keys::store::AccountProvider; use util::numbers::*; use ethcore::client::BlockChainClient; use ethminer::MinerService; diff --git a/rpc/src/v1/impls/personal_signer.rs b/rpc/src/v1/impls/personal_signer.rs new file mode 100644 index 000000000..cf4e927ac --- /dev/null +++ b/rpc/src/v1/impls/personal_signer.rs @@ -0,0 +1,93 @@ +// 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 . + +//! Transactions Confirmations (personal) rpc implementation + +use std::sync::{Arc, Weak}; +use jsonrpc_core::*; +use v1::traits::PersonalSigner; +use v1::types::TransactionModification; +use v1::impls::sign_and_dispatch; +use v1::helpers::{SigningQueue, ConfirmationsQueue}; +use util::keys::store::AccountProvider; +use util::numbers::*; +use ethcore::client::BlockChainClient; +use ethminer::MinerService; + +/// Transactions confirmation (personal) rpc implementation. +pub struct SignerClient + where A: AccountProvider, C: BlockChainClient, M: MinerService { + queue: Weak, + accounts: Weak, + client: Weak, + miner: Weak, +} + +impl SignerClient + where A: AccountProvider, C: BlockChainClient, M: MinerService { + + /// Create new instance of signer client. + pub fn new(store: &Arc, client: &Arc, miner: &Arc, queue: &Arc) -> Self { + SignerClient { + queue: Arc::downgrade(queue), + accounts: Arc::downgrade(store), + client: Arc::downgrade(client), + miner: Arc::downgrade(miner), + } + } +} + +impl PersonalSigner for SignerClient + where A: AccountProvider, C: BlockChainClient, M: MinerService { + + fn transactions_to_confirm(&self, _params: Params) -> Result { + let queue = take_weak!(self.queue); + to_value(&queue.requests()) + } + + fn confirm_transaction(&self, params: Params) -> Result { + from_params::<(U256, TransactionModification, String)>(params).and_then( + |(id, modification, pass)| { + let accounts = take_weak!(self.accounts); + let queue = take_weak!(self.queue); + queue.remove_request(id) + .and_then(|confirmation| { + let mut request = confirmation.transaction; + // apply modification + if let Some(gas_price) = modification.gas_price { + request.gas_price = Some(gas_price); + } + match accounts.locked_account_secret(&request.from, &pass) { + Ok(secret) => Some(sign_and_dispatch(&self.client, &self.miner, request, secret)), + Err(_) => None + } + }) + .unwrap_or_else(|| to_value(&H256::zero())) + } + ) + } + + fn reject_transaction(&self, params: Params) -> Result { + from_params::<(U256, )>(params).and_then( + |(id, )| { + let queue = take_weak!(self.queue); + let res = queue.remove_request(id); + to_value(&res.is_some()) + } + ) + } +} + diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index b1ab256c0..54628d892 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -25,5 +25,6 @@ pub mod traits; pub mod tests; pub mod types; -pub use self::traits::{Web3, Eth, EthFilter, Personal, Net, Ethcore, Traces, Rpc}; +pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalSigner, Net, Ethcore, Traces, Rpc}; pub use self::impls::*; +pub use self::helpers::{SigningQueue, ConfirmationsQueue}; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 30815b8a8..80aa8ce33 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -35,8 +35,8 @@ use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; use ethjson::blockchain::BlockChain; -use v1::traits::eth::Eth; -use v1::impls::EthClient; +use v1::traits::eth::{Eth, EthSigning}; +use v1::impls::{EthClient, EthSigningUnsafeClient}; use v1::tests::helpers::{TestSyncProvider, Config}; fn account_provider() -> Arc { @@ -109,10 +109,15 @@ impl EthTester { &miner_service, &external_miner ); + let eth_sign = EthSigningUnsafeClient::new( + &client, + &account_provider, + &miner_service + ); let handler = IoHandler::new(); - let delegate = eth_client.to_delegate(); - handler.add_delegate(delegate); + handler.add_delegate(eth_client.to_delegate()); + handler.add_delegate(eth_sign.to_delegate()); EthTester { _miner: miner_service, @@ -352,4 +357,4 @@ fn verify_transaction_counts(name: String, chain: BlockChain) { register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest"); register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest"); -register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest"); \ No newline at end of file +register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest"); diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index c51d6d7da..49ca54cef 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -27,7 +27,7 @@ use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; use ethminer::{ExternalMiner, MinerService}; use ethsync::SyncState; -use v1::{Eth, EthClient}; +use v1::{Eth, EthClient, EthSigning, EthSigningUnsafeClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use rustc_serialize::hex::ToHex; @@ -72,8 +72,11 @@ impl Default for EthTester { let hashrates = Arc::new(RwLock::new(HashMap::new())); let external_miner = Arc::new(ExternalMiner::new(hashrates.clone())); let eth = EthClient::new(&client, &sync, &ap, &miner, &external_miner).to_delegate(); + let sign = EthSigningUnsafeClient::new(&client, &ap, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(eth); + io.add_delegate(sign); + EthTester { client: client, sync: sync, diff --git a/rpc/src/v1/tests/mocked/eth_signing.rs b/rpc/src/v1/tests/mocked/eth_signing.rs new file mode 100644 index 000000000..6eb6e3fd6 --- /dev/null +++ b/rpc/src/v1/tests/mocked/eth_signing.rs @@ -0,0 +1,75 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::impls::EthSigningQueueClient; +use v1::traits::EthSigning; +use v1::helpers::{ConfirmationsQueue, SigningQueue}; +use util::keys::TestAccount; + +struct EthSigningTester { + pub queue: Arc, + pub io: IoHandler, +} + +impl Default for EthSigningTester { + fn default() -> Self { + let queue = Arc::new(ConfirmationsQueue::default()); + let io = IoHandler::new(); + io.add_delegate(EthSigningQueueClient::new(&queue).to_delegate()); + + EthSigningTester { + queue: queue, + io: io, + } + } +} + +fn eth_signing() -> EthSigningTester { + EthSigningTester::default() +} + + +#[test] +fn should_add_transaction_to_queue() { + // given + let tester = eth_signing(); + let account = TestAccount::new("123"); + let address = account.address(); + assert_eq!(tester.queue.requests().len(), 0); + + // when + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a" + }], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#; + + + // then + assert_eq!(tester.io.handle_request(&request), Some(response.to_owned())); + assert_eq!(tester.queue.requests().len(), 1); + +} diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index dc09d998d..986dbfdef 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -18,8 +18,10 @@ //! method calls properly. mod eth; +mod eth_signing; mod net; mod web3; mod personal; +mod personal_signer; mod ethcore; mod rpc; diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 991b13cba..8bc3ab3c8 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -176,4 +176,4 @@ fn sign_and_send_transaction() { let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); -} \ No newline at end of file +} diff --git a/rpc/src/v1/tests/mocked/personal_signer.rs b/rpc/src/v1/tests/mocked/personal_signer.rs new file mode 100644 index 000000000..cd1f81d9a --- /dev/null +++ b/rpc/src/v1/tests/mocked/personal_signer.rs @@ -0,0 +1,169 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use std::str::FromStr; +use std::collections::HashMap; +use jsonrpc_core::IoHandler; +use util::numbers::*; +use util::keys::{TestAccount, TestAccountProvider}; +use ethcore::client::TestBlockChainClient; +use ethcore::transaction::{Transaction, Action}; +use v1::{SignerClient, PersonalSigner}; +use v1::tests::helpers::TestMinerService; +use v1::helpers::{SigningQueue, ConfirmationsQueue}; +use v1::types::TransactionRequest; + + +struct PersonalSignerTester { + queue: Arc, + accounts: Arc, + io: IoHandler, + miner: Arc, + // these unused fields are necessary to keep the data alive + // as the handler has only weak pointers. + _client: Arc, +} + +fn blockchain_client() -> Arc { + let client = TestBlockChainClient::new(); + Arc::new(client) +} + +fn accounts_provider() -> Arc { + let accounts = HashMap::new(); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn miner_service() -> Arc { + Arc::new(TestMinerService::default()) +} + +fn signer_tester() -> PersonalSignerTester { + let queue = Arc::new(ConfirmationsQueue::default()); + let accounts = accounts_provider(); + let client = blockchain_client(); + let miner = miner_service(); + + let io = IoHandler::new(); + io.add_delegate(SignerClient::new(&accounts, &client, &miner, &queue).to_delegate()); + + PersonalSignerTester { + queue: queue, + accounts: accounts, + io: io, + miner: miner, + _client: client, + } +} + + +#[test] +fn should_return_list_of_transactions_in_queue() { + // given + let tester = signer_tester(); + tester.queue.add_request(TransactionRequest { + from: Address::from(1), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from(10_000)), + gas: Some(U256::from(10_000_000)), + value: Some(U256::from(1)), + data: None, + nonce: None, + }); + + // when + let request = r#"{"jsonrpc":"2.0","method":"personal_transactionsToConfirm","params":[],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":[{"id":"0x01","transaction":{"data":null,"from":"0x0000000000000000000000000000000000000001","gas":"0x989680","gasPrice":"0x2710","nonce":null,"to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","value":"0x01"}}],"id":1}"#; + + // then + assert_eq!(tester.io.handle_request(&request), Some(response.to_owned())); +} + + +#[test] +fn should_reject_transaction_from_queue_without_dispatching() { + // given + let tester = signer_tester(); + tester.queue.add_request(TransactionRequest { + from: Address::from(1), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from(10_000)), + gas: Some(U256::from(10_000_000)), + value: Some(U256::from(1)), + data: None, + nonce: None, + }); + assert_eq!(tester.queue.requests().len(), 1); + + // when + let request = r#"{"jsonrpc":"2.0","method":"personal_rejectTransaction","params":["0x01"],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + // then + assert_eq!(tester.io.handle_request(&request), Some(response.to_owned())); + assert_eq!(tester.queue.requests().len(), 0); + assert_eq!(tester.miner.imported_transactions.lock().unwrap().len(), 0); +} + +#[test] +fn should_confirm_transaction_and_dispatch() { + // given + let tester = signer_tester(); + let account = TestAccount::new("test"); + let address = account.address(); + let secret = account.secret.clone(); + let recipient = Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap(); + tester.accounts.accounts + .write() + .unwrap() + .insert(address, account); + tester.queue.add_request(TransactionRequest { + from: address, + to: Some(recipient), + gas_price: Some(U256::from(10_000)), + gas: Some(U256::from(10_000_000)), + value: Some(U256::from(1)), + data: None, + nonce: None, + }); + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x1000), + gas: U256::from(10_000_000), + action: Action::Call(recipient), + value: U256::from(0x1), + data: vec![] + }.sign(&secret); + + assert_eq!(tester.queue.requests().len(), 1); + + // when + let request = r#"{ + "jsonrpc":"2.0", + "method":"personal_confirmTransaction", + "params":["0x01", {"gasPrice":"0x1000"}, "test"], + "id":1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + + // then + assert_eq!(tester.io.handle_request(&request), Some(response.to_owned())); + assert_eq!(tester.queue.requests().len(), 0); + assert_eq!(tester.miner.imported_transactions.lock().unwrap().len(), 1); +} + diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 1577053f4..c4369ff2a 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -74,12 +74,6 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns the code at given address at given time (block number). fn code_at(&self, _: Params) -> Result; - /// Signs the data with given address signature. - fn sign(&self, _: Params) -> Result; - - /// Sends transaction. - fn send_transaction(&self, _: Params) -> Result; - /// Sends signed transaction. fn send_raw_transaction(&self, _: Params) -> Result; @@ -150,8 +144,6 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count_by_hash); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count_by_number); delegate.add_method("eth_getCode", Eth::code_at); - delegate.add_method("eth_sign", Eth::sign); - delegate.add_method("eth_sendTransaction", Eth::send_transaction); delegate.add_method("eth_sendRawTransaction", Eth::send_raw_transaction); delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_estimateGas", Eth::estimate_gas); @@ -208,3 +200,20 @@ pub trait EthFilter: Sized + Send + Sync + 'static { delegate } } + +/// Signing methods implementation relying on unlocked accounts. +pub trait EthSigning: Sized + Send + Sync + 'static { + /// Signs the data with given address signature. + fn sign(&self, _: Params) -> Result; + + /// Sends transaction. + fn send_transaction(&self, _: Params) -> Result; + + /// Should be used to convert object to io delegate. + fn to_delegate(self) -> IoDelegate { + let mut delegate = IoDelegate::new(Arc::new(self)); + delegate.add_method("eth_sign", EthSigning::sign); + delegate.add_method("eth_sendTransaction", EthSigning::send_transaction); + delegate + } +} diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 0728fd06a..d994ffc24 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -25,9 +25,11 @@ pub mod traces; pub mod rpc; pub use self::web3::Web3; -pub use self::eth::{Eth, EthFilter}; +pub use self::eth::{Eth, EthFilter, EthSigning}; pub use self::net::Net; -pub use self::personal::Personal; +pub use self::personal::{Personal, PersonalSigner}; pub use self::ethcore::Ethcore; pub use self::traces::Traces; pub use self::rpc::Rpc; + + diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs index d66161c54..a36358766 100644 --- a/rpc/src/v1/traits/personal.rs +++ b/rpc/src/v1/traits/personal.rs @@ -43,3 +43,26 @@ pub trait Personal: Sized + Send + Sync + 'static { delegate } } + +/// Personal extension for transactions confirmations rpc interface. +pub trait PersonalSigner: Sized + Send + Sync + 'static { + + /// Returns a list of transactions to confirm. + fn transactions_to_confirm(&self, _: Params) -> Result; + + /// Confirm and send a specific transaction. + fn confirm_transaction(&self, _: Params) -> Result; + + /// Reject the transaction request. + fn reject_transaction(&self, _: Params) -> Result; + + /// Should be used to convert object to io delegate. + fn to_delegate(self) -> IoDelegate { + let mut delegate = IoDelegate::new(Arc::new(self)); + delegate.add_method("personal_transactionsToConfirm", PersonalSigner::transactions_to_confirm); + delegate.add_method("personal_confirmTransaction", PersonalSigner::confirm_transaction); + delegate.add_method("personal_rejectTransaction", PersonalSigner::reject_transaction); + delegate + } +} + diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 824a061ef..b4e82a28b 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -38,7 +38,7 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; -pub use self::transaction_request::TransactionRequest; +pub use self::transaction_request::{TransactionRequest, TransactionConfirmation, TransactionModification}; pub use self::call_request::CallRequest; pub use self::receipt::Receipt; pub use self::trace::Trace; diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index 1b51e6b12..93d6a479b 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -21,7 +21,7 @@ use util::numbers::U256; use v1::types::bytes::Bytes; /// Transaction request coming from RPC -#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Deserialize)] +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct TransactionRequest { /// Sender pub from: Address, @@ -40,6 +40,24 @@ pub struct TransactionRequest { pub nonce: Option, } +/// Transaction confirmation waiting in a queue +#[derive(Debug, Clone, Default, Eq, PartialEq, Hash, Serialize)] +pub struct TransactionConfirmation { + /// Id of this confirmation + pub id: U256, + /// TransactionRequest + pub transaction: TransactionRequest, +} + +/// Possible modifications to the confirmed transaction sent by SystemUI +#[derive(Debug, PartialEq, Deserialize)] +pub struct TransactionModification { + /// Modified gas price + #[serde(rename="gasPrice")] + pub gas_price: Option, +} + + #[cfg(test)] mod tests { use std::str::FromStr; @@ -135,5 +153,26 @@ mod tests { nonce: None, }); } + + #[test] + fn should_deserialize_modification() { + // given + let s1 = r#"{ + "gasPrice":"0x0ba43b7400" + }"#; + let s2 = r#"{}"#; + + // when + let res1: TransactionModification = serde_json::from_str(s1).unwrap(); + let res2: TransactionModification = serde_json::from_str(s2).unwrap(); + + // then + assert_eq!(res1, TransactionModification { + gas_price: Some(U256::from_str("0ba43b7400").unwrap()), + }); + assert_eq!(res2, TransactionModification { + gas_price: None, + }); + } } diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 51b1b1e8d..170c9320e 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -9,13 +9,8 @@ build = "build.rs" [build-dependencies] rustc_version = "0.1" -serde_codegen = { version = "0.7.0", optional = true } -syntex = "^0.32.0" [dependencies] -serde = "0.7.0" -serde_json = "0.7.0" -rustc-serialize = "0.3" jsonrpc-core = "2.0" log = "0.3" env_logger = "0.3" @@ -23,10 +18,7 @@ ws = "0.4.7" ethcore-util = { path = "../util" } ethcore-rpc = { path = "../rpc" } -serde_macros = { version = "0.7.0", optional = true } clippy = { version = "0.0.69", optional = true} [features] -default = ["serde_codegen"] -nightly = ["serde_macros"] dev = ["clippy"] diff --git a/signer/build.rs b/signer/build.rs index 2bcfc7da5..41b9a1b3e 100644 --- a/signer/build.rs +++ b/signer/build.rs @@ -19,34 +19,7 @@ extern crate rustc_version; use rustc_version::{version_meta, Channel}; fn main() { - serde::main(); if let Channel::Nightly = version_meta().channel { println!("cargo:rustc-cfg=nightly"); } } - -#[cfg(not(feature = "serde_macros"))] -mod serde { - extern crate syntex; - extern crate serde_codegen; - - use std::env; - use std::path::Path; - - pub fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - - let src = Path::new("src/types/mod.rs.in"); - let dst = Path::new(&out_dir).join("mod.rs"); - - let mut registry = syntex::Registry::new(); - - serde_codegen::register(&mut registry); - registry.expand("", &src, &dst).unwrap(); - } -} - -#[cfg(feature = "serde_macros")] -mod serde { - pub fn main() {} -} diff --git a/signer/src/lib.rs b/signer/src/lib.rs index f3a963ac7..e2df72bcc 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -17,8 +17,6 @@ #![warn(missing_docs)] #![cfg_attr(all(nightly, feature="dev"), feature(plugin))] #![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] -// Generated by serde -#![cfg_attr(all(nightly, feature="dev"), allow(redundant_closure_call))] //! Signer module //! @@ -45,18 +43,12 @@ extern crate log; extern crate env_logger; -extern crate serde; -extern crate serde_json; -extern crate rustc_serialize; - extern crate ethcore_util as util; extern crate ethcore_rpc as rpc; extern crate jsonrpc_core; extern crate ws; -mod signing_queue; mod ws_server; - pub use ws_server::*; #[cfg(test)] diff --git a/signer/src/signing_queue.rs b/signer/src/signing_queue.rs deleted file mode 100644 index 611d467c2..000000000 --- a/signer/src/signing_queue.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::collections::HashSet; -use rpc::v1::types::TransactionRequest; - -pub trait SigningQueue { - fn add_request(&mut self, transaction: TransactionRequest); - - fn remove_request(&mut self, id: TransactionRequest); - - fn requests(&self) -> &HashSet; -} - -impl SigningQueue for HashSet { - fn add_request(&mut self, transaction: TransactionRequest) { - self.insert(transaction); - } - - fn remove_request(&mut self, id: TransactionRequest) { - self.remove(&id); - } - - fn requests(&self) -> &HashSet { - self - } -} - - -#[cfg(test)] -mod test { - use std::collections::HashSet; - use util::hash::Address; - use util::numbers::U256; - use rpc::v1::types::TransactionRequest; - use super::*; - - #[test] - fn should_work_for_hashset() { - // given - let mut queue = HashSet::new(); - - let request = TransactionRequest { - from: Address::from(1), - to: Some(Address::from(2)), - gas_price: None, - gas: None, - value: Some(U256::from(10_000_000)), - data: None, - nonce: None, - }; - - // when - queue.add_request(request.clone()); - let all = queue.requests(); - - // then - assert_eq!(all.len(), 1); - assert!(all.contains(&request)); - } -} diff --git a/signer/src/types/mod.rs b/signer/src/types/mod.rs deleted file mode 100644 index d5e15046a..000000000 --- a/signer/src/types/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 . - -//! Reusable types with JSON Serialization. - -#[cfg(feature = "serde_macros")] -include!("mod.rs.in"); - -#[cfg(not(feature = "serde_macros"))] -include!(concat!(env!("OUT_DIR"), "/mod.rs")); diff --git a/signer/src/types/mod.rs.in b/signer/src/types/mod.rs.in deleted file mode 100644 index a59f81ece..000000000 --- a/signer/src/types/mod.rs.in +++ /dev/null @@ -1,25 +0,0 @@ -// 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 . - - - - - - - - - -// TODO [ToDr] Types are empty for now. But they are about to come. diff --git a/signer/src/ws_server/mod.rs b/signer/src/ws_server/mod.rs index bb10bc5c1..bc8fb33f8 100644 --- a/signer/src/ws_server/mod.rs +++ b/signer/src/ws_server/mod.rs @@ -25,6 +25,7 @@ use std::sync::Arc; use std::net::SocketAddr; use util::panics::{PanicHandler, OnPanicListener, MayPanic}; use jsonrpc_core::{IoHandler, IoDelegate}; +use rpc::Extendable; mod session; @@ -57,6 +58,12 @@ impl Default for ServerBuilder { } } +impl Extendable for ServerBuilder { + fn add_delegate(&self, delegate: IoDelegate) { + self.handler.add_delegate(delegate); + } +} + impl ServerBuilder { /// Creates new `ServerBuilder` pub fn new() -> Self { @@ -65,11 +72,6 @@ impl ServerBuilder { } } - /// Adds rpc delegate - pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { - self.handler.add_delegate(delegate); - } - /// Starts a new `WebSocket` server in separate thread. /// Returns a `Server` handle which closes the server when droped. pub fn start(self, addr: SocketAddr) -> Result { From c370bcaded498e1e4c42b9c8d42674881f344ade Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 19:57:34 +0200 Subject: [PATCH 83/88] merge fixes --- parity/rpc_apis.rs | 2 +- rpc/src/v1/impls/eth.rs | 183 ---------------------------- rpc/src/v1/impls/eth_filter.rs | 2 +- rpc/src/v1/impls/eth_signing.rs | 10 +- rpc/src/v1/impls/personal_signer.rs | 10 +- 5 files changed, 12 insertions(+), 195 deletions(-) diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index c73a70fee..d9f0cd4eb 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -20,7 +20,7 @@ use std::sync::Arc; use die::*; use ethsync::EthSync; -use ethminer::{Miner, ExternalMiner}; +use ethcore::miner::{Miner, ExternalMiner}; use ethcore::client::Client; use util::RotatingLogger; use util::keys::store::AccountService; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 1af4491f2..83a788599 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -544,186 +544,3 @@ impl Eth for EthClient where rpc_unimplemented!() } } - -/// Eth filter rpc implementation. -pub struct EthFilterClient where - C: MiningBlockChainClient, - M: MinerService { - - client: Weak, - miner: Weak, - polls: Mutex>, -} - -impl EthFilterClient where - C: MiningBlockChainClient, - M: MinerService { - - /// Creates new Eth filter client. - pub fn new(client: &Arc, miner: &Arc) -> Self { - EthFilterClient { - client: Arc::downgrade(client), - miner: Arc::downgrade(miner), - polls: Mutex::new(PollManager::new()), - } - } -} - -impl EthFilter for EthFilterClient where - C: MiningBlockChainClient + 'static, - M: MinerService + 'static { - - fn new_filter(&self, params: Params) -> Result { - from_params::<(Filter,)>(params) - .and_then(|(filter,)| { - let mut polls = self.polls.lock().unwrap(); - let block_number = take_weak!(self.client).chain_info().best_block_number; - let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter)); - to_value(&U256::from(id)) - }) - } - - fn new_block_filter(&self, params: Params) -> Result { - match params { - Params::None => { - let mut polls = self.polls.lock().unwrap(); - let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); - to_value(&U256::from(id)) - }, - _ => Err(Error::invalid_params()) - } - } - - fn new_pending_transaction_filter(&self, params: Params) -> Result { - match params { - Params::None => { - let mut polls = self.polls.lock().unwrap(); - let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); - let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); - - to_value(&U256::from(id)) - }, - _ => Err(Error::invalid_params()) - } - } - - fn filter_changes(&self, params: Params) -> Result { - let client = take_weak!(self.client); - from_params::<(Index,)>(params) - .and_then(|(index,)| { - let mut polls = self.polls.lock().unwrap(); - match polls.poll_mut(&index.value()) { - None => Ok(Value::Array(vec![] as Vec)), - Some(filter) => match *filter { - PollFilter::Block(ref mut block_number) => { - // + 1, cause we want to return hashes including current block hash. - let current_number = client.chain_info().best_block_number + 1; - let hashes = (*block_number..current_number).into_iter() - .map(BlockID::Number) - .filter_map(|id| client.block_hash(id)) - .collect::>(); - - *block_number = current_number; - - to_value(&hashes) - }, - PollFilter::PendingTransaction(ref mut previous_hashes) => { - // get hashes of pending transactions - let current_hashes = take_weak!(self.miner).pending_transactions_hashes(); - - let new_hashes = - { - let previous_hashes_set = previous_hashes.iter().collect::>(); - - // find all new hashes - current_hashes - .iter() - .filter(|hash| !previous_hashes_set.contains(hash)) - .cloned() - .collect::>() - }; - - // save all hashes of pending transactions - *previous_hashes = current_hashes; - - // return new hashes - to_value(&new_hashes) - }, - PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => { - // retrive the current block number - let current_number = client.chain_info().best_block_number; - - // check if we need to check pending hashes - let include_pending = filter.to_block == Some(BlockNumber::Pending); - - // build appropriate filter - let mut filter: EthcoreFilter = filter.clone().into(); - filter.from_block = BlockID::Number(*block_number); - filter.to_block = BlockID::Latest; - - // retrieve logs in range from_block..min(BlockID::Latest..to_block) - let mut logs = client.logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - - // additionally retrieve pending logs - if include_pending { - let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter); - - // remove logs about which client was already notified about - let new_pending_logs: Vec<_> = pending_logs.iter() - .filter(|p| !previous_logs.contains(p)) - .cloned() - .collect(); - - // save all logs retrieved by client - *previous_logs = pending_logs.into_iter().collect(); - - // append logs array with new pending logs - logs.extend(new_pending_logs); - } - - // save current block number as next from block number - *block_number = current_number; - - to_value(&logs) - } - } - } - }) - } - - fn filter_logs(&self, params: Params) -> Result { - from_params::<(Index,)>(params) - .and_then(|(index,)| { - let mut polls = self.polls.lock().unwrap(); - match polls.poll(&index.value()) { - Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => { - let include_pending = filter.to_block == Some(BlockNumber::Pending); - let filter: EthcoreFilter = filter.clone().into(); - let mut logs = take_weak!(self.client).logs(filter.clone()) - .into_iter() - .map(From::from) - .collect::>(); - - if include_pending { - logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter)); - } - - to_value(&logs) - }, - // just empty array - _ => Ok(Value::Array(vec![] as Vec)), - } - }) - } - - fn uninstall_filter(&self, params: Params) -> Result { - from_params::<(Index,)>(params) - .and_then(|(index,)| { - self.polls.lock().unwrap().remove_poll(&index.value()); - to_value(&true) - }) - } -} diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index c6aecdca2..4f44f5193 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -21,7 +21,7 @@ use std::sync::{Arc, Weak, Mutex}; use std::collections::HashSet; use jsonrpc_core::*; use util::numbers::*; -use ethminer::MinerService; +use ethcore::miner::MinerService; use ethcore::filter::Filter as EthcoreFilter; use ethcore::client::{BlockChainClient, BlockID}; use v1::traits::EthFilter; diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs index 04011902b..f0973484f 100644 --- a/rpc/src/v1/impls/eth_signing.rs +++ b/rpc/src/v1/impls/eth_signing.rs @@ -18,8 +18,8 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; -use ethminer::MinerService; -use ethcore::client::BlockChainClient; +use ethcore::miner::MinerService; +use ethcore::client::MiningBlockChainClient; use util::numbers::*; use util::keys::store::AccountProvider; use v1::helpers::{SigningQueue, ConfirmationsQueue}; @@ -62,7 +62,7 @@ impl EthSigning for EthSigningQueueClient { /// Implementation of functions that require signing when no trusted signer is used. pub struct EthSigningUnsafeClient where - C: BlockChainClient, + C: MiningBlockChainClient, A: AccountProvider, M: MinerService { client: Weak, @@ -71,7 +71,7 @@ pub struct EthSigningUnsafeClient where } impl EthSigningUnsafeClient where - C: BlockChainClient, + C: MiningBlockChainClient, A: AccountProvider, M: MinerService { @@ -87,7 +87,7 @@ impl EthSigningUnsafeClient where } impl EthSigning for EthSigningUnsafeClient where - C: BlockChainClient + 'static, + C: MiningBlockChainClient + 'static, A: AccountProvider + 'static, M: MinerService + 'static { diff --git a/rpc/src/v1/impls/personal_signer.rs b/rpc/src/v1/impls/personal_signer.rs index cf4e927ac..2d52e07f9 100644 --- a/rpc/src/v1/impls/personal_signer.rs +++ b/rpc/src/v1/impls/personal_signer.rs @@ -24,12 +24,12 @@ use v1::impls::sign_and_dispatch; use v1::helpers::{SigningQueue, ConfirmationsQueue}; use util::keys::store::AccountProvider; use util::numbers::*; -use ethcore::client::BlockChainClient; -use ethminer::MinerService; +use ethcore::client::MiningBlockChainClient; +use ethcore::miner::MinerService; /// Transactions confirmation (personal) rpc implementation. pub struct SignerClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { queue: Weak, accounts: Weak, client: Weak, @@ -37,7 +37,7 @@ pub struct SignerClient } impl SignerClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { /// Create new instance of signer client. pub fn new(store: &Arc, client: &Arc, miner: &Arc, queue: &Arc) -> Self { @@ -51,7 +51,7 @@ impl SignerClient } impl PersonalSigner for SignerClient - where A: AccountProvider, C: BlockChainClient, M: MinerService { + where A: AccountProvider, C: MiningBlockChainClient, M: MinerService { fn transactions_to_confirm(&self, _params: Params) -> Result { let queue = take_weak!(self.queue); From b7ada4dee02ec2fc08415a2a3302c8aea92729e9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 1 Jun 2016 20:10:51 +0200 Subject: [PATCH 84/88] update readme (#1201) * update readme [ci skip] * minor fixes * mention dapps server. [ci skip] --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 903794e80..193cbeb8f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# ethcore +# [Parity](https://ethcore.io/parity.html) +### Fast, light, and robust Ethereum implementation [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/trogdoro/xiki][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url] @@ -11,30 +12,64 @@ [license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg [license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html -[Documentation](http://ethcore.github.io/parity/ethcore/index.html) +[Internal Documentation](http://ethcore.github.io/parity/ethcore/index.html) -### Building from source +---- -First (if you don't already have it) get multirust: +## About Parity + +Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and +cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. + +By default, Parity will run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number +of RPC APIs. + +Parity also runs a server for running decentralized apps, or "Dapps", on `http://127.0.0.1:8080`. +This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a node status page. +In a near-future release, it will be easy to install Dapps and use them through this web interface. + +If you run into an issue while using parity, feel free to file one in this repository +or hop on our [gitter chat room]([gitter-url]) to ask a question. We are glad to help! + +Parity's current release is 1.1. You can download it at https://ethcore.io/parity.html or follow the instructions +below to build from source. + +---- + +## Building from source + +Parity is fully compatible with Stable Rust. + +We recommend installing Rust through [multirust](https://github.com/brson/multirust). If you don't already have multirust, you can install it like this: - Linux: ```bash -curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh +$ curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sh ``` - OSX with Homebrew: ```bash -brew update && brew install multirust -multirust default stable +$ brew update && brew install multirust +$ multirust default stable ``` Then, download and build Parity: ```bash # download Parity code -git clone https://github.com/ethcore/parity -cd parity +$ git clone https://github.com/ethcore/parity +$ cd parity # build in release mode -cargo build --release +$ cargo build --release ``` + +This will produce an executable in the `target/release` subdirectory. +Either run `cd target/release`, or copy `target/release/parity` to another location. + +To get started, just run +```bash +$ parity +``` + +and parity will begin syncing the Ethereum blockchain. \ No newline at end of file From 626acda6a3275df74578826f1538d53362926720 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 1 Jun 2016 20:11:05 +0200 Subject: [PATCH 85/88] fix warnings --- parity/dapps.rs | 4 ---- parity/rpc.rs | 4 ---- parity/signer.rs | 4 ---- 3 files changed, 12 deletions(-) diff --git a/parity/dapps.rs b/parity/dapps.rs index 6a0a8cea7..91742d9e3 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -17,10 +17,6 @@ use std::sync::Arc; use std::str::FromStr; use std::net::SocketAddr; -use ethcore::client::Client; -use ethsync::EthSync; -use ethcore::miner::{Miner, ExternalMiner}; -use util::RotatingLogger; use util::panics::PanicHandler; use die::*; use rpc_apis; diff --git a/parity/rpc.rs b/parity/rpc.rs index 65e6b72e1..66f504408 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -18,10 +18,6 @@ use std::str::FromStr; use std::sync::Arc; use std::net::SocketAddr; -use ethcore::client::Client; -use ethsync::EthSync; -use ethcore::miner::{Miner, ExternalMiner}; -use util::RotatingLogger; use util::panics::PanicHandler; use die::*; use jsonipc; diff --git a/parity/signer.rs b/parity/signer.rs index c250771eb..d549b89cb 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -15,10 +15,6 @@ // along with Parity. If not, see . use std::sync::Arc; -use ethcore::client::Client; -use ethsync::EthSync; -use ethcore::miner::{Miner, ExternalMiner}; -use util::keys::store::AccountService; use util::panics::{PanicHandler, ForwardPanic}; use die::*; use rpc_apis; From 8596a347ead1c053e50ebc6f412bacc9e50182ec Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 2 Jun 2016 11:49:56 +0200 Subject: [PATCH 86/88] Networking refactoring (#1172) * Networking refactoring * Make sure the same socket is reused * Safer atomic ordering * Replaced eq with == --- Cargo.lock | 7 +- util/Cargo.toml | 2 +- util/src/network/connection.rs | 59 ++------ util/src/network/handshake.rs | 54 ++------ util/src/network/host.rs | 245 ++++++++++----------------------- util/src/network/session.rs | 151 ++++++++++++++------ 6 files changed, 209 insertions(+), 309 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce5c1f481..723bca872 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,7 +390,7 @@ dependencies = [ "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", - "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1176,6 +1176,11 @@ name = "slab" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "slab" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "solicit" version = "0.4.4" diff --git a/util/Cargo.toml b/util/Cargo.toml index 7d03fd320..a88ffe037 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -25,7 +25,7 @@ elastic-array = "0.4" heapsize = "0.3" itertools = "0.4" crossbeam = "0.2" -slab = "0.1" +slab = "0.2" sha3 = { path = "sha3" } serde = "0.7.0" clippy = { version = "0.0.69", optional = true} diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 589fc0106..3f20b8f7b 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -170,16 +170,16 @@ impl Connection { self.token } - /// Replace socket token - pub fn set_token(&mut self, token: StreamToken) { - self.token = token; - } - /// Get remote peer address pub fn remote_addr(&self) -> io::Result { self.socket.peer_addr() } + /// Get remote peer address string + pub fn remote_addr_str(&self) -> String { + self.socket.peer_addr().map(|a| a.to_string()).unwrap_or_else(|_| "Unknown".to_owned()) + } + /// Clone this connection. Clears the receiving buffer of the returned connection. pub fn try_clone(&self) -> io::Result { Ok(Connection { @@ -196,7 +196,7 @@ impl Connection { /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "network", "connection register; token={:?}", reg); - if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()) { + if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() /* | PollOpt::oneshot() */) { // TODO: oneshot is broken on windows trace!(target: "network", "Failed to register {:?}, {:?}", reg, e); } Ok(()) @@ -205,7 +205,7 @@ impl Connection { /// Update connection registration. Should be called at the end of the IO handler. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "network", "connection reregister; token={:?}", reg); - event_loop.reregister( &self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { + event_loop.reregister( &self.socket, reg, self.interest, PollOpt::edge() /* | PollOpt::oneshot() */ ).or_else(|e| { // TODO: oneshot is broken on windows trace!(target: "network", "Failed to reregister {:?}, {:?}", reg, e); Ok(()) }) @@ -246,7 +246,7 @@ enum EncryptedConnectionState { /// https://github.com/ethereum/devp2p/blob/master/rlpx.md#framing pub struct EncryptedConnection { /// Underlying tcp connection - connection: Connection, + pub connection: Connection, /// Egress data encryptor encoder: CtrMode, /// Ingress data decryptor @@ -266,27 +266,6 @@ pub struct EncryptedConnection { } impl EncryptedConnection { - - /// Get socket token - pub fn token(&self) -> StreamToken { - self.connection.token - } - - /// Replace socket token - pub fn set_token(&mut self, token: StreamToken) { - self.connection.set_token(token); - } - - /// Get remote peer address - pub fn remote_addr(&self) -> io::Result { - self.connection.remote_addr() - } - - /// Check if this connection has data to be sent. - pub fn is_sending(&self) -> bool { - self.connection.is_sending() - } - /// Create an encrypted connection out of the handshake. Consumes a handshake object. pub fn new(handshake: &mut Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_ephemeral)); @@ -323,8 +302,10 @@ impl EncryptedConnection { ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); + let old_connection = try!(handshake.connection.try_clone()); + let connection = ::std::mem::replace(&mut handshake.connection, old_connection); let mut enc = EncryptedConnection { - connection: try!(handshake.connection.try_clone()), + connection: connection, encoder: encoder, decoder: decoder, mac_encoder: mac_encoder, @@ -463,24 +444,6 @@ impl EncryptedConnection { try!(self.connection.writable()); Ok(()) } - - /// Register socket with the event lpop. This should be called at the end of the event loop. - pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.register_socket(reg, event_loop)); - Ok(()) - } - - /// Update connection registration. This should be called at the end of the event loop. - pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.update_socket(reg, event_loop)); - Ok(()) - } - - /// Delete connection registration. This should be called at the end of the event loop. - pub fn deregister_socket(&self, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.deregister_socket(event_loop)); - Ok(()) - } } #[test] diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 123531d8d..e02da3d4c 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -16,7 +16,6 @@ use std::sync::Arc; use rand::random; -use mio::*; use mio::tcp::*; use hash::*; use rlp::*; @@ -102,21 +101,6 @@ impl Handshake { }) } - /// Get id of the remote node if known - pub fn id(&self) -> &NodeId { - &self.id - } - - /// Get stream token id - pub fn token(&self) -> StreamToken { - self.connection.token() - } - - /// Mark this handshake as inactive to be deleted lated. - pub fn set_expired(&mut self) { - self.expired = true; - } - /// Check if this handshake is expired. pub fn expired(&self) -> bool { self.expired @@ -177,7 +161,7 @@ impl Handshake { } /// Writabe IO handler. - pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { + pub fn writable(&mut self, io: &IoContext) -> Result<(), UtilError> where Message: Send + Clone { if !self.expired() { io.clear_timer(self.connection.token).unwrap(); try!(self.connection.writable()); @@ -188,28 +172,6 @@ impl Handshake { Ok(()) } - /// Register the socket with the event loop - pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - if !self.expired() { - try!(self.connection.register_socket(reg, event_loop)); - } - Ok(()) - } - - /// Update socket registration with the event loop. - pub fn update_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - if !self.expired() { - try!(self.connection.update_socket(reg, event_loop)); - } - Ok(()) - } - - /// Delete registration - pub fn deregister_socket(&self, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.deregister_socket(event_loop)); - Ok(()) - } - fn set_auth(&mut self, host_secret: &Secret, sig: &[u8], remote_public: &[u8], remote_nonce: &[u8], remote_version: u64) -> Result<(), UtilError> { self.id.clone_from_slice(remote_public); self.remote_nonce.clone_from_slice(remote_nonce); @@ -222,7 +184,7 @@ impl Handshake { /// Parse, validate and confirm auth message fn read_auth(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"network", "Received handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received handshake auth from {:?}", self.connection.remote_addr_str()); if data.len() != V4_AUTH_PACKET_SIZE { debug!(target:"net", "Wrong auth packet size"); return Err(From::from(NetworkError::BadProtocol)); @@ -253,7 +215,7 @@ impl Handshake { } fn read_auth_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.auth_cipher.extend_from_slice(data); let auth = try!(ecies::decrypt(secret, &self.auth_cipher[0..2], &self.auth_cipher[2..])); let rlp = UntrustedRlp::new(&auth); @@ -268,7 +230,7 @@ impl Handshake { /// Parse and validate ack message fn read_ack(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"network", "Received handshake auth to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received handshake auth to {:?}", self.connection.remote_addr_str()); if data.len() != V4_ACK_PACKET_SIZE { debug!(target:"net", "Wrong ack packet size"); return Err(From::from(NetworkError::BadProtocol)); @@ -296,7 +258,7 @@ impl Handshake { } fn read_ack_eip8(&mut self, secret: &Secret, data: &[u8]) -> Result<(), UtilError> { - trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Received EIP8 handshake auth from {:?}", self.connection.remote_addr_str()); self.ack_cipher.extend_from_slice(data); let ack = try!(ecies::decrypt(secret, &self.ack_cipher[0..2], &self.ack_cipher[2..])); let rlp = UntrustedRlp::new(&ack); @@ -309,7 +271,7 @@ impl Handshake { /// Sends auth message fn write_auth(&mut self, secret: &Secret, public: &Public) -> Result<(), UtilError> { - trace!(target:"network", "Sending handshake auth to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending handshake auth to {:?}", self.connection.remote_addr_str()); let mut data = [0u8; /*Signature::SIZE*/ 65 + /*H256::SIZE*/ 32 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32 + 1]; //TODO: use associated constants let len = data.len(); { @@ -336,7 +298,7 @@ impl Handshake { /// Sends ack message fn write_ack(&mut self) -> Result<(), UtilError> { - trace!(target:"network", "Sending handshake ack to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending handshake ack to {:?}", self.connection.remote_addr_str()); let mut data = [0u8; 1 + /*Public::SIZE*/ 64 + /*H256::SIZE*/ 32]; //TODO: use associated constants let len = data.len(); { @@ -355,7 +317,7 @@ impl Handshake { /// Sends EIP8 ack message fn write_ack_eip8(&mut self) -> Result<(), UtilError> { - trace!(target:"network", "Sending EIP8 handshake ack to {:?}", self.connection.socket.peer_addr()); + trace!(target:"network", "Sending EIP8 handshake ack to {:?}", self.connection.remote_addr_str()); let mut rlp = RlpStream::new_list(3); rlp.append(self.ecdhe.public()); rlp.append(&self.nonce); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 13b64eb3c..92a912a40 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -18,6 +18,7 @@ use std::net::{SocketAddr}; use std::collections::{HashMap}; use std::str::{FromStr}; use std::sync::*; +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::ops::*; use std::cmp::min; use std::path::{Path, PathBuf}; @@ -31,7 +32,6 @@ use misc::version; use crypto::*; use sha3::Hashable; use rlp::*; -use network::handshake::Handshake; use network::session::{Session, SessionData}; use error::*; use io::*; @@ -44,8 +44,7 @@ use network::ip_utils::{map_external_address, select_public_address}; type Slab = ::slab::Slab; -const _DEFAULT_PORT: u16 = 30304; -const MAX_SESSIONS: usize = 1024; +const MAX_SESSIONS: usize = 1024 + MAX_HANDSHAKES; const MAX_HANDSHAKES: usize = 80; const MAX_HANDSHAKES_PER_ROUND: usize = 32; const MAINTENANCE_TIMEOUT: u64 = 1000; @@ -115,18 +114,17 @@ impl NetworkConfiguration { } // Tokens -const TCP_ACCEPT: usize = LAST_HANDSHAKE + 1; -const IDLE: usize = LAST_HANDSHAKE + 2; -const DISCOVERY: usize = LAST_HANDSHAKE + 3; -const DISCOVERY_REFRESH: usize = LAST_HANDSHAKE + 4; -const DISCOVERY_ROUND: usize = LAST_HANDSHAKE + 5; -const INIT_PUBLIC: usize = LAST_HANDSHAKE + 6; -const NODE_TABLE: usize = LAST_HANDSHAKE + 7; +const TCP_ACCEPT: usize = SYS_TIMER + 1; +const IDLE: usize = SYS_TIMER + 2; +const DISCOVERY: usize = SYS_TIMER + 3; +const DISCOVERY_REFRESH: usize = SYS_TIMER + 4; +const DISCOVERY_ROUND: usize = SYS_TIMER + 5; +const INIT_PUBLIC: usize = SYS_TIMER + 6; +const NODE_TABLE: usize = SYS_TIMER + 7; const FIRST_SESSION: usize = 0; const LAST_SESSION: usize = FIRST_SESSION + MAX_SESSIONS - 1; -const FIRST_HANDSHAKE: usize = LAST_SESSION + 1; -const LAST_HANDSHAKE: usize = FIRST_HANDSHAKE + MAX_HANDSHAKES - 1; -const USER_TIMER: usize = LAST_HANDSHAKE + 256; +const USER_TIMER: usize = LAST_SESSION + 256; +const SYS_TIMER: usize = LAST_SESSION + 1; /// Protocol handler level packet id pub type PacketId = u8; @@ -306,7 +304,6 @@ impl HostInfo { } type SharedSession = Arc>; -type SharedHandshake = Arc>; #[derive(Copy, Clone)] struct ProtocolTimer { @@ -318,7 +315,6 @@ struct ProtocolTimer { pub struct Host where Message: Send + Sync + Clone { pub info: RwLock, tcp_listener: Mutex, - handshakes: Arc>>, sessions: Arc>>, discovery: Mutex>, nodes: RwLock, @@ -327,6 +323,7 @@ pub struct Host where Message: Send + Sync + Clone { timer_counter: RwLock, stats: Arc, pinned_nodes: Vec, + num_sessions: AtomicUsize, } impl Host where Message: Send + Sync + Clone { @@ -370,7 +367,6 @@ impl Host where Message: Send + Sync + Clone { }), discovery: Mutex::new(None), tcp_listener: Mutex::new(tcp_listener), - handshakes: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_HANDSHAKE, MAX_HANDSHAKES))), sessions: Arc::new(RwLock::new(Slab::new_starting_at(FIRST_SESSION, MAX_SESSIONS))), nodes: RwLock::new(NodeTable::new(path)), handlers: RwLock::new(HashMap::new()), @@ -378,6 +374,7 @@ impl Host where Message: Send + Sync + Clone { timer_counter: RwLock::new(USER_TIMER), stats: Arc::new(NetworkStats::default()), pinned_nodes: Vec::new(), + num_sessions: AtomicUsize::new(0), }; let boot_nodes = host.info.read().unwrap().config.boot_nodes.clone(); @@ -477,19 +474,19 @@ impl Host where Message: Send + Sync + Clone { } fn have_session(&self, id: &NodeId) -> bool { - self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().info.id.eq(&id)) + self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().info.id == Some(id.clone())) } fn session_count(&self) -> usize { - self.sessions.read().unwrap().count() + self.num_sessions.load(AtomicOrdering::Relaxed) } fn connecting_to(&self, id: &NodeId) -> bool { - self.handshakes.read().unwrap().iter().any(|e| e.lock().unwrap().id.eq(&id)) + self.sessions.read().unwrap().iter().any(|e| e.lock().unwrap().id() == Some(id)) } fn handshake_count(&self) -> usize { - self.handshakes.read().unwrap().count() + self.sessions.read().unwrap().count() - self.session_count() } fn keep_alive(&self, io: &IoContext>) { @@ -565,21 +562,31 @@ impl Host where Message: Send + Sync + Clone { } } }; - self.create_connection(socket, Some(id), io); + if let Err(e) = self.create_connection(socket, Some(id), io) { + debug!(target: "network", "Can't create connection: {:?}", e); + } } #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] - fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { + fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) -> Result<(), UtilError> { let nonce = self.info.write().unwrap().next_nonce(); - let mut handshakes = self.handshakes.write().unwrap(); - if handshakes.insert_with(|token| { - let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake"); - handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| { - debug!(target: "network", "Handshake create error: {:?}", e); - }); - Arc::new(Mutex::new(handshake)) - }).is_none() { - debug!(target: "network", "Max handshakes reached"); + let mut sessions = self.sessions.write().unwrap(); + let token = sessions.insert_with_opt(|token| { + match Session::new(io, socket, token, id, &nonce, self.stats.clone(), &self.info.read().unwrap()) { + Ok(s) => Some(Arc::new(Mutex::new(s))), + Err(e) => { + debug!(target: "network", "Session create error: {:?}", e); + None + } + } + }); + + match token { + Some(t) => io.register_stream(t), + None => { + debug!(target: "network", "Max sessions reached"); + Ok(()) + } } } @@ -594,19 +601,11 @@ impl Host where Message: Send + Sync + Clone { break }, }; - self.create_connection(socket, None, io); - } - io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener"); - } - - fn handshake_writable(&self, token: StreamToken, io: &IoContext>) { - let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; - if let Some(handshake) = handshake { - let mut h = handshake.lock().unwrap(); - if let Err(e) = h.writable(io, &self.info.read().unwrap()) { - trace!(target: "network", "Handshake write error: {}: {:?}", token, e); + if let Err(e) = self.create_connection(socket, None, io) { + debug!(target: "network", "Can't accept connection: {:?}", e); } } + io.update_registration(TCP_ACCEPT).expect("Error registering TCP listener"); } fn session_writable(&self, token: StreamToken, io: &IoContext>) { @@ -629,30 +628,6 @@ impl Host where Message: Send + Sync + Clone { self.kill_connection(token, io, true); } - fn handshake_readable(&self, token: StreamToken, io: &IoContext>) { - let mut create_session = false; - let mut kill = false; - let handshake = { self.handshakes.read().unwrap().get(token).cloned() }; - if let Some(handshake) = handshake { - let mut h = handshake.lock().unwrap(); - if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "network", "Handshake read error: {}: {:?}", token, e); - kill = true; - } - if h.done() { - create_session = true; - } - } - if kill { - self.kill_connection(token, io, true); - return; - } else if create_session { - self.start_session(token, io); - return; - } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); - } - fn session_readable(&self, token: StreamToken, io: &IoContext>) { let mut ready_data: Vec = Vec::new(); let mut packet_data: Option<(ProtocolId, PacketId, Vec)> = None; @@ -662,17 +637,37 @@ impl Host where Message: Send + Sync + Clone { let mut s = session.lock().unwrap(); match s.readable(io, &self.info.read().unwrap()) { Err(e) => { - trace!(target: "network", "Session read error: {}:{} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); + trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e); match e { UtilError::Network(NetworkError::Disconnect(DisconnectReason::UselessPeer)) | UtilError::Network(NetworkError::Disconnect(DisconnectReason::IncompatibleProtocol)) => { - self.nodes.write().unwrap().mark_as_useless(s.id()); + if let Some(id) = s.id() { + self.nodes.write().unwrap().mark_as_useless(id); + } } _ => (), } kill = true; }, Ok(SessionData::Ready) => { + if !s.info.originated { + let session_count = self.session_count(); + let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; + if session_count >= ideal_peers as usize { + s.disconnect(DisconnectReason::TooManyPeers); + return; + } + // Add it no node table + if let Ok(address) = s.remote_addr() { + let entry = NodeEntry { id: s.id().unwrap().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; + self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); + let mut discovery = self.discovery.lock().unwrap(); + if let Some(ref mut discovery) = *discovery.deref_mut() { + discovery.add_node(entry); + } + } + } + self.num_sessions.fetch_add(1, AtomicOrdering::SeqCst); for (p, _) in self.handlers.read().unwrap().iter() { if s.have_capability(p) { ready_data.push(p); @@ -697,6 +692,7 @@ impl Host where Message: Send + Sync + Clone { } for p in ready_data { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); + self.stats.inc_sessions(); h.connected(&NetworkContext::new(io, p, session.clone(), self.sessions.clone()), &token); } if let Some((p, packet_id, data)) = packet_data { @@ -706,59 +702,6 @@ impl Host where Message: Send + Sync + Clone { io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } - fn start_session(&self, token: StreamToken, io: &IoContext>) { - let mut handshakes = self.handshakes.write().unwrap(); - if handshakes.get(token).is_none() { - return; - } - - // turn a handshake into a session - let mut sessions = self.sessions.write().unwrap(); - let mut h = handshakes.get_mut(token).unwrap().lock().unwrap(); - if h.expired { - return; - } - io.deregister_stream(token).expect("Error deleting handshake registration"); - h.set_expired(); - let originated = h.originated; - let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { - Ok(s) => s, - Err(e) => { - debug!(target: "network", "Session creation error: {:?}", e); - return; - } - }; - if !originated { - let session_count = sessions.count(); - let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; - if session_count >= ideal_peers as usize { - session.disconnect(DisconnectReason::TooManyPeers); - return; - } - } - let result = sessions.insert_with(move |session_token| { - session.set_token(session_token); - io.register_stream(session_token).expect("Error creating session registration"); - self.stats.inc_sessions(); - trace!(target: "network", "Creating session {} -> {}:{} ({:?})", token, session_token, session.id(), session.remote_addr()); - if !originated { - // Add it no node table - if let Ok(address) = session.remote_addr() { - let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; - self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); - let mut discovery = self.discovery.lock().unwrap(); - if let Some(ref mut discovery) = *discovery.deref_mut() { - discovery.add_node(entry); - } - } - } - Arc::new(Mutex::new(session)) - }); - if result.is_none() { - warn!("Max sessions reached"); - } - } - fn connection_timeout(&self, token: StreamToken, io: &IoContext>) { trace!(target: "network", "Connection timeout: {}", token); self.kill_connection(token, io, true) @@ -770,17 +713,6 @@ impl Host where Message: Send + Sync + Clone { let mut deregister = false; let mut expired_session = None; match token { - FIRST_HANDSHAKE ... LAST_HANDSHAKE => { - let handshakes = self.handshakes.write().unwrap(); - if let Some(handshake) = handshakes.get(token).cloned() { - let mut handshake = handshake.lock().unwrap(); - if !handshake.expired() { - handshake.set_expired(); - failure_id = Some(handshake.id().clone()); - deregister = true; - } - } - }, FIRST_SESSION ... LAST_SESSION => { let sessions = self.sessions.write().unwrap(); if let Some(session) = sessions.get(token).cloned() { @@ -790,12 +722,13 @@ impl Host where Message: Send + Sync + Clone { if s.is_ready() { for (p, _) in self.handlers.read().unwrap().iter() { if s.have_capability(p) { + self.num_sessions.fetch_sub(1, AtomicOrdering::SeqCst); to_disconnect.push(p); } } } s.set_expired(); - failure_id = Some(s.id().clone()); + failure_id = s.id().cloned(); } deregister = remote || s.done(); } @@ -821,20 +754,11 @@ impl Host where Message: Send + Sync + Clone { fn update_nodes(&self, io: &IoContext>, node_changes: TableUpdates) { let mut to_remove: Vec = Vec::new(); { - { - let handshakes = self.handshakes.write().unwrap(); - for c in handshakes.iter() { - let h = c.lock().unwrap(); - if node_changes.removed.contains(&h.id()) { - to_remove.push(h.token()); - } - } - } - { - let sessions = self.sessions.write().unwrap(); - for c in sessions.iter() { - let s = c.lock().unwrap(); - if node_changes.removed.contains(&s.id()) { + let sessions = self.sessions.write().unwrap(); + for c in sessions.iter() { + let s = c.lock().unwrap(); + if let Some(id) = s.id() { + if node_changes.removed.contains(id) { to_remove.push(s.token()); } } @@ -860,7 +784,6 @@ impl IoHandler> for Host where Messa trace!(target: "network", "Hup: {}", stream); match stream { FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io), - FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io), _ => warn!(target: "network", "Unexpected hup"), }; } @@ -868,7 +791,6 @@ impl IoHandler> for Host where Messa fn stream_readable(&self, io: &IoContext>, stream: StreamToken) { match stream { FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), - FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { let node_changes = { self.discovery.lock().unwrap().as_mut().unwrap().readable() }; if let Some(node_changes) = node_changes { @@ -884,7 +806,6 @@ impl IoHandler> for Host where Messa fn stream_writable(&self, io: &IoContext>, stream: StreamToken) { match stream { FIRST_SESSION ... LAST_SESSION => self.session_writable(stream, io), - FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_writable(stream, io), DISCOVERY => { self.discovery.lock().unwrap().as_mut().unwrap().writable(); io.update_registration(DISCOVERY).expect("Error updating discovery registration"); @@ -899,7 +820,6 @@ impl IoHandler> for Host where Messa INIT_PUBLIC => self.init_public_interface(io).unwrap_or_else(|e| warn!("Error initializing public interface: {:?}", e)), FIRST_SESSION ... LAST_SESSION => self.connection_timeout(token, io), - FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_timeout(token, io), DISCOVERY_REFRESH => { self.discovery.lock().unwrap().as_mut().unwrap().refresh(); io.update_registration(DISCOVERY).expect("Error updating discovery registration"); @@ -966,7 +886,9 @@ impl IoHandler> for Host where Messa let session = { self.sessions.read().unwrap().get(*peer).cloned() }; if let Some(session) = session { session.lock().unwrap().disconnect(DisconnectReason::DisconnectRequested); - self.nodes.write().unwrap().mark_as_useless(session.lock().unwrap().id()); + if let Some(id) = session.lock().unwrap().id() { + self.nodes.write().unwrap().mark_as_useless(id) + } } trace!(target: "network", "Disabling peer {}", peer); self.kill_connection(*peer, io, false); @@ -987,12 +909,6 @@ impl IoHandler> for Host where Messa session.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); } } - FIRST_HANDSHAKE ... LAST_HANDSHAKE => { - let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; - if let Some(connection) = connection { - connection.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); - } - } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().register_socket(event_loop).expect("Error registering discovery socket"), TCP_ACCEPT => event_loop.register(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error registering stream"), _ => warn!("Unexpected stream registration") @@ -1008,13 +924,6 @@ impl IoHandler> for Host where Messa connections.remove(stream); } } - FIRST_HANDSHAKE ... LAST_HANDSHAKE => { - let mut connections = self.handshakes.write().unwrap(); - if let Some(connection) = connections.get(stream).cloned() { - connection.lock().unwrap().deregister_socket(event_loop).expect("Error deregistering socket"); - connections.remove(stream); - } - } DISCOVERY => (), _ => warn!("Unexpected stream deregistration") } @@ -1028,12 +937,6 @@ impl IoHandler> for Host where Messa connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); } } - FIRST_HANDSHAKE ... LAST_HANDSHAKE => { - let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; - if let Some(connection) = connection { - connection.lock().unwrap().update_socket(reg, event_loop).expect("Error updating socket"); - } - } DISCOVERY => self.discovery.lock().unwrap().as_ref().unwrap().update_registration(event_loop).expect("Error reregistering discovery socket"), TCP_ACCEPT => event_loop.reregister(self.tcp_listener.lock().unwrap().deref(), Token(TCP_ACCEPT), EventSet::all(), PollOpt::edge()).expect("Error reregistering stream"), _ => warn!("Unexpected stream update") diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 6c0a20a14..7b7f16c18 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -16,15 +16,19 @@ use std::net::SocketAddr; use std::io; +use std::sync::*; use mio::*; +use mio::tcp::*; use rlp::*; -use network::connection::{EncryptedConnection, Packet}; +use hash::*; +use network::connection::{EncryptedConnection, Packet, Connection}; use network::handshake::Handshake; use error::*; use io::{IoContext, StreamToken}; use network::error::{NetworkError, DisconnectReason}; use network::host::*; use network::node_table::NodeId; +use network::stats::NetworkStats; use time; const PING_TIMEOUT_SEC: u64 = 30; @@ -36,14 +40,18 @@ const PING_INTERVAL_SEC: u64 = 30; pub struct Session { /// Shared session information pub info: SessionInfo, - /// Underlying connection - connection: EncryptedConnection, /// Session ready flag. Set after successfull Hello packet exchange had_hello: bool, /// Session is no longer active flag. expired: bool, ping_time_ns: u64, pong_time_ns: Option, + state: State, +} + +enum State { + Handshake(Handshake), + Session(EncryptedConnection), } /// Structure used to report various session events. @@ -65,7 +73,7 @@ pub enum SessionData { /// Shared session information pub struct SessionInfo { /// Peer public key - pub id: NodeId, + pub id: Option, /// Peer client ID pub client_version: String, /// Peer RLPx protocol version @@ -74,6 +82,8 @@ pub struct SessionInfo { capabilities: Vec, /// Peer ping delay in milliseconds pub ping_ms: Option, + /// True if this session was originated by us. + pub originated: bool, } #[derive(Debug, PartialEq, Eq)] @@ -112,31 +122,52 @@ const PACKET_LAST: u8 = 0x7f; impl Session { /// Create a new session out of comepleted handshake. This clones the handshake connection object /// and leaves the handhsake in limbo to be deregistered from the event loop. - pub fn new(h: &mut Handshake, host: &HostInfo) -> Result { - let id = h.id.clone(); - let connection = try!(EncryptedConnection::new(h)); - let mut session = Session { - connection: connection, + pub fn new(io: &IoContext, socket: TcpStream, token: StreamToken, id: Option<&NodeId>, + nonce: &H256, stats: Arc, host: &HostInfo) -> Result + where Message: Send + Clone { + let originated = id.is_some(); + let mut handshake = Handshake::new(token, id, socket, &nonce, stats).expect("Can't create handshake"); + try!(handshake.start(io, host, originated)); + Ok(Session { + state: State::Handshake(handshake), had_hello: false, info: SessionInfo { - id: id, + id: id.cloned(), client_version: String::new(), protocol_version: 0, capabilities: Vec::new(), ping_ms: None, + originated: originated, }, ping_time_ns: 0, pong_time_ns: None, expired: false, + }) + } + + fn complete_handshake(&mut self, host: &HostInfo) -> Result<(), UtilError> { + let connection = if let State::Handshake(ref mut h) = self.state { + self.info.id = Some(h.id.clone()); + try!(EncryptedConnection::new(h)) + } else { + panic!("Unexpected state"); }; - try!(session.write_hello(host)); - try!(session.send_ping()); - Ok(session) + self.state = State::Session(connection); + try!(self.write_hello(host)); + try!(self.send_ping()); + Ok(()) + } + + fn connection(&self) -> &Connection { + match self.state { + State::Handshake(ref h) => &h.connection, + State::Session(ref s) => &s.connection, + } } /// Get id of the remote peer - pub fn id(&self) -> &NodeId { - &self.info.id + pub fn id(&self) -> Option<&NodeId> { + self.info.id.as_ref() } /// Check if session is ready to send/receive data @@ -151,21 +182,20 @@ impl Session { /// Check if this session is expired. pub fn expired(&self) -> bool { - self.expired + match self.state { + State::Handshake(ref h) => h.expired(), + _ => self.expired, + } } /// Check if this session is over and there is nothing to be sent. pub fn done(&self) -> bool { - self.expired() && !self.connection.is_sending() - } - /// Replace socket token - pub fn set_token(&mut self, token: StreamToken) { - self.connection.set_token(token); + self.expired() && !self.connection().is_sending() } /// Get remote peer address pub fn remote_addr(&self) -> io::Result { - self.connection.remote_addr() + self.connection().remote_addr() } /// Readable IO handler. Returns packet data if available. @@ -173,15 +203,37 @@ impl Session { if self.expired() { return Ok(SessionData::None) } - match try!(self.connection.readable(io)) { - Some(data) => Ok(try!(self.read_packet(data, host))), - None => Ok(SessionData::None) + let mut create_session = false; + let mut packet_data = None; + match self.state { + State::Handshake(ref mut h) => { + try!(h.readable(io, host)); + if h.done() { + create_session = true; + } + } + State::Session(ref mut c) => { + match try!(c.readable(io)) { + data @ Some(_) => packet_data = data, + None => return Ok(SessionData::None) + } + } } + if let Some(data) = packet_data { + return Ok(try!(self.read_packet(data, host))); + } + if create_session { + try!(self.complete_handshake(host)); + } + Ok(SessionData::None) } /// Writable IO handler. Sends pending packets. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Sync + Clone { - self.connection.writable(io) + match self.state { + State::Handshake(ref mut h) => h.writable(io), + State::Session(ref mut s) => s.writable(io), + } } /// Checks if peer supports given capability @@ -194,18 +246,20 @@ impl Session { if self.expired() { return Ok(()); } - try!(self.connection.register_socket(reg, event_loop)); + try!(self.connection().register_socket(reg, event_loop)); Ok(()) } /// Update registration with the event loop. Should be called at the end of the IO handler. pub fn update_socket(&self, reg:Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - self.connection.update_socket(reg, event_loop) + try!(self.connection().update_socket(reg, event_loop)); + Ok(()) } /// Delete registration pub fn deregister_socket(&self, event_loop: &mut EventLoop) -> Result<(), UtilError> { - self.connection.deregister_socket(event_loop) + try!(self.connection().deregister_socket(event_loop)); + Ok(()) } /// Send a protocol packet to peer. @@ -221,7 +275,7 @@ impl Session { while protocol != self.info.capabilities[i].protocol { i += 1; if i == self.info.capabilities.len() { - debug!(target: "net", "Unknown protocol: {:?}", protocol); + debug!(target: "network", "Unknown protocol: {:?}", protocol); return Ok(()) } } @@ -229,11 +283,14 @@ impl Session { let mut rlp = RlpStream::new(); rlp.append(&(pid as u32)); rlp.append_raw(data, 1); - self.connection.send_packet(&rlp.out()) + self.send(rlp) } /// Keep this session alive. Returns false if ping timeout happened pub fn keep_alive(&mut self, io: &IoContext) -> bool where Message: Send + Sync + Clone { + if let State::Handshake(_) = self.state { + return true; + } let timed_out = if let Some(pong) = self.pong_time_ns { pong - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000 } else { @@ -244,13 +301,13 @@ impl Session { if let Err(e) = self.send_ping() { debug!("Error sending ping message: {:?}", e); } - io.update_registration(self.token()).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + io.update_registration(self.token()).unwrap_or_else(|e| debug!(target: "network", "Session registration error: {:?}", e)); } !timed_out } pub fn token(&self) -> StreamToken { - self.connection.token() + self.connection().token() } fn read_packet(&mut self, packet: Packet, host: &HostInfo) -> Result { @@ -288,7 +345,7 @@ impl Session { while packet_id < self.info.capabilities[i].id_offset { i += 1; if i == self.info.capabilities.len() { - debug!(target: "net", "Unknown packet: {:?}", packet_id); + debug!(target: "network", "Unknown packet: {:?}", packet_id); return Ok(SessionData::None) } } @@ -299,7 +356,7 @@ impl Session { Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: pid } ) }, _ => { - debug!(target: "net", "Unknown packet: {:?}", packet_id); + debug!(target: "network", "Unknown packet: {:?}", packet_id); Ok(SessionData::None) } } @@ -314,7 +371,7 @@ impl Session { .append(&host.capabilities) .append(&host.local_endpoint.address.port()) .append(host.id()); - self.connection.send_packet(&rlp.out()) + self.send(rlp) } fn read_hello(&mut self, rlp: &UntrustedRlp, host: &HostInfo) -> Result<(), UtilError> { @@ -384,11 +441,13 @@ impl Session { /// Disconnect this session pub fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError { - let mut rlp = RlpStream::new(); - rlp.append(&(PACKET_DISCONNECT as u32)); - rlp.begin_list(1); - rlp.append(&(reason as u32)); - self.connection.send_packet(&rlp.out()).ok(); + if let State::Session(_) = self.state { + let mut rlp = RlpStream::new(); + rlp.append(&(PACKET_DISCONNECT as u32)); + rlp.begin_list(1); + rlp.append(&(reason as u32)); + self.send(rlp).ok(); + } NetworkError::Disconnect(reason) } @@ -400,7 +459,15 @@ impl Session { } fn send(&mut self, rlp: RlpStream) -> Result<(), UtilError> { - self.connection.send_packet(&rlp.out()) + match self.state { + State::Handshake(_) => { + warn!(target:"network", "Unexpected send request"); + }, + State::Session(ref mut s) => { + try!(s.send_packet(&rlp.out())) + }, + } + Ok(()) } } From 7ad9c73c7523d3183ec4e84ed4b66a9abeac741a Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 2 Jun 2016 11:51:03 +0200 Subject: [PATCH 87/88] devtools helpers extended (#1186) * devtools extensions * some doc effort --- devtools/src/lib.rs | 2 ++ devtools/src/random_path.rs | 12 +++++++++- devtools/src/stop_guard.rs | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 devtools/src/stop_guard.rs diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs index 3ab585d93..e37d5c528 100644 --- a/devtools/src/lib.rs +++ b/devtools/src/lib.rs @@ -21,6 +21,8 @@ extern crate rand; pub mod random_path; pub mod test_socket; +pub mod stop_guard; pub use random_path::*; pub use test_socket::*; +pub use stop_guard::*; diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs index 990d375e3..09bee7e45 100644 --- a/devtools/src/random_path.rs +++ b/devtools/src/random_path.rs @@ -26,7 +26,11 @@ pub struct RandomTempPath { } pub fn random_filename() -> String { - (0..8).map(|_| ((random::() * 26.0) as u8 + 97) as char).collect() + random_str(8) +} + +pub fn random_str(len: usize) -> String { + (0..len).map(|_| ((random::() * 26.0) as u8 + 97) as char).collect() } impl RandomTempPath { @@ -54,6 +58,12 @@ impl RandomTempPath { pub fn as_str(&self) -> &str { self.path.to_str().unwrap() } + + pub fn new_in(&self, name: &str) -> String { + let mut path = self.path.clone(); + path.push(name); + path.to_str().unwrap().to_owned() + } } impl Drop for RandomTempPath { diff --git a/devtools/src/stop_guard.rs b/devtools/src/stop_guard.rs new file mode 100644 index 000000000..f1db59725 --- /dev/null +++ b/devtools/src/stop_guard.rs @@ -0,0 +1,45 @@ +// 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 . + +//! Stop guard mod + +use std::sync::Arc; +use std::sync::atomic::*; + +/// Stop guard that will set a stop flag on drop +pub struct StopGuard { + flag: Arc, +} + +impl StopGuard { + /// Create a stop guard + pub fn new() -> StopGuard { + StopGuard { + flag: Arc::new(AtomicBool::new(false)) + } + } + + /// Share stop guard between the threads + pub fn share(&self) -> Arc { + self.flag.clone() + } +} + +impl Drop for StopGuard { + fn drop(&mut self) { + self.flag.store(true, Ordering::Relaxed) + } +} From b17581d7ded39250602b6d15324ff5bff26f26c1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 2 Jun 2016 12:40:31 +0200 Subject: [PATCH 88/88] VM tracing and JSON RPC endpoint for it. (#1169) * Groundwork for basic VM tracing. * RPC endpoint for VM tracing and ser/de types ready. * Create VMTracer trait. * Rearchitected VM tracing to reflect existing tracing. Should more or less work now. * Integrated VM tracing into JSONRPC. * Fix ethcore module tests. * Add tests for VM tracing. * Fix consensus test code. * Fix mock tests. * Added VM trace information for post-execution stuff. * Fix max-value calls and add "creates" field to getTransaction. * Tests for VM tracing. * Don't implement the trait with unimplemented. * Remove invlaid comment. * Fix tests. --- ethcore/res/ethereum/morden.json | 11 +- ethcore/src/client/client.rs | 8 +- ethcore/src/client/mod.rs | 3 +- ethcore/src/client/test_client.rs | 2 +- ethcore/src/evm/ext.rs | 6 + ethcore/src/evm/instructions.rs | 3 +- ethcore/src/evm/interpreter.rs | 63 +++++++- ethcore/src/evm/jit.rs | 1 + ethcore/src/evm/mod.rs | 1 + ethcore/src/executive.rs | 188 +++++++++++++++++----- ethcore/src/externalities.rs | 44 +++-- ethcore/src/json_tests/executive.rs | 36 +++-- ethcore/src/lib.rs | 2 + ethcore/src/miner/miner.rs | 7 +- ethcore/src/miner/mod.rs | 2 +- ethcore/src/state.rs | 8 +- ethcore/src/trace/executive_tracer.rs | 52 +++++- ethcore/src/trace/mod.rs | 27 +++- ethcore/src/trace/noop_tracer.rs | 24 ++- ethcore/src/types/executed.rs | 4 +- ethcore/src/types/trace_types/trace.rs | 164 +++++++++++++++++++ json/src/state/transaction.rs | 2 +- parity/rpc_apis.rs | 2 +- rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 8 +- rpc/src/v1/impls/ethcore.rs | 99 +++++++++++- rpc/src/v1/tests/eth.rs | 3 +- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 6 +- rpc/src/v1/tests/mocked/ethcore.rs | 61 ++++--- rpc/src/v1/traits/ethcore.rs | 4 + rpc/src/v1/types/block.rs | 2 +- rpc/src/v1/types/transaction.rs | 19 ++- util/src/common.rs | 7 + util/src/rlp/rlpstream.rs | 12 ++ util/src/rlp/untrusted_rlp.rs | 30 ++-- 36 files changed, 742 insertions(+), 172 deletions(-) diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 1e385558d..0cc88ac64 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -34,17 +34,8 @@ "gasLimit": "0x2fefd8" }, "nodes": [ - "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303", - "enode://7ee7195bfac561ec938a72cd84cd1a5d2b334415263feddc325b20b5010446fc6c361297d13decab4039028fa659c1e27cca1396574b87cc7b29eea2985e97fe@108.61.197.28:30303", - "enode://933c5d5470b77537e7d9c1ee686132b5032dd3e2a096d2f64d2004df4ce9fca4ad6da5e358edcc8f81e65f047e40045600181f5fb35066e771025f6cca8e7952@46.101.114.191:30303", - "enode://ad4028ba28783d5bf58f512cb4e24a8ce980d768177c4974e1140b16b925132c947349db9ca3646752891b382dafc839a0c0716c3764c1ed9d424f09d13d01cf@148.251.220.116:30303", - "enode://c54ddaacddc7029683c80edae91015520eb2712176fbe6fdb7a5a074659270638f1266cba1731681c7cb785bceb02ca8d8b23024e3ec736fc5579f2042be97ae@54.175.255.230:30303", - "enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303", "enode://e731347db0521f3476e6bbbb83375dcd7133a1601425ebd15fd10f3835fd4c304fba6282087ca5a0deeafadf0aa0d4fd56c3323331901c1f38bd181c283e3e35@128.199.55.137:30303", - "enode://e941c58fed2709d792f552f408d2162c3d0a5597d22d1da617a9c9e6181f3251056a96adb45ae22eba70119355227298dc7e6dff805b092bae7da2f8564de422@85.25.217.23:30303", - "enode://f4b73c9d11a780293ff0ca7afa12c67797afdc33a4797a7c2ecc5b87e455b32a8b9e9804f2004072bac38350bf82d52521d1a09590d2079705fc8357aef2bf9c@71.202.223.50:56603", - "enode://1173eea53e0cb2b8da92423e44cf4cbafbc8ea16c1558cf06e18dfc5a2fc9b140cc802a4362b4c773fb1442541e6f2a225b200bb4c1f6b347e7510a50fa4873f@104.41.138.167:30300", - "enode://1aad341327808738ad34655611f1b13293c4155dde36c8e3788128829f15cc6db2da9435f29520553d4efc134aadc50115690194ac3af519aac7a388b524811e@109.188.125.2:30303" + "enode://ceb5c0f85eb994dbe9693bf46d99b03f6b838d17cc74e68d5eb003171ff39e5f120b17f965b267c319303f94d80b9d994b77062fb1486d76ce95d9f3d8fe1cb4@46.101.122.141:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3aaeb02c3..3ddf7018a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -436,7 +436,7 @@ impl Client where V: Verifier { } impl BlockChainClient for Client where V: Verifier { - fn call(&self, t: &SignedTransaction) -> Result { + fn call(&self, t: &SignedTransaction, vm_tracing: bool) -> Result { let header = self.block_header(BlockID::Latest).unwrap(); let view = HeaderView::new(&header); let last_hashes = self.build_last_hashes(view.hash()); @@ -456,10 +456,10 @@ impl BlockChainClient for Client where V: Verifier { ExecutionError::TransactionMalformed(message) })); let balance = state.balance(&sender); - // give the sender max balance + // give the sender a decent balance state.sub_balance(&sender, &balance); - state.add_balance(&sender, &U256::max_value()); - let options = TransactOptions { tracing: false, check_nonce: false }; + state.add_balance(&sender, &(U256::from(1) << 200)); + let options = TransactOptions { tracing: false, vm_tracing: vm_tracing, check_nonce: false }; Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options) } diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 3f64cb620..84eea7494 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -157,7 +157,8 @@ pub trait BlockChainClient : Sync + Send { fn logs(&self, filter: Filter) -> Vec; /// Makes a non-persistent transaction call. - fn call(&self, t: &SignedTransaction) -> Result; + // TODO: should be able to accept blockchain location for call. + fn call(&self, t: &SignedTransaction, vm_tracing: bool) -> Result; /// Returns EvmFactory. fn vm_factory(&self) -> &EvmFactory; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 83799c78f..f3768d0a6 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -251,7 +251,7 @@ impl MiningBlockChainClient for TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { - fn call(&self, _t: &SignedTransaction) -> Result { + fn call(&self, _t: &SignedTransaction, _vm_tracing: bool) -> Result { Ok(self.execution_result.read().unwrap().clone().unwrap()) } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index 4986b12c8..1c21e467a 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -105,4 +105,10 @@ pub trait Ext { /// Increments sstore refunds count by 1. fn inc_sstore_clears(&mut self); + + /// Prepare to trace an operation. Passthrough for the VM trace. + fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false } + + /// Trace the finalised execution of a single instruction. + fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {} } diff --git a/ethcore/src/evm/instructions.rs b/ethcore/src/evm/instructions.rs index 6a1a06ba9..c313726f1 100644 --- a/ethcore/src/evm/instructions.rs +++ b/ethcore/src/evm/instructions.rs @@ -124,6 +124,7 @@ pub struct InstructionInfo { pub side_effects: bool, pub tier: GasPriceTier } + impl InstructionInfo { pub fn new(name: &'static str, additional: usize, args: usize, ret: usize, side_effects: bool, tier: GasPriceTier) -> InstructionInfo { InstructionInfo { @@ -139,7 +140,7 @@ impl InstructionInfo { #[cfg_attr(rustfmt, rustfmt_skip)] /// Return details about specific instruction -pub fn get_info (instruction: Instruction) -> InstructionInfo { +pub fn get_info(instruction: Instruction) -> InstructionInfo { match instruction { STOP => InstructionInfo::new("STOP", 0, 0, 0, true, GasPriceTier::Zero), ADD => InstructionInfo::new("ADD", 0, 2, 1, false, GasPriceTier::VeryLow), diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index eb29ef257..9cf4d6034 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -17,8 +17,9 @@ ///! Rust VM implementation use common::*; +use trace::VMTracer; use super::instructions as instructions; -use super::instructions::Instruction; +use super::instructions::{Instruction, get_info}; use std::marker::Copy; use evm::{self, MessageCallResult, ContractCreateResult}; @@ -69,6 +70,8 @@ trait Stack { fn push(&mut self, elem: T); /// Get number of elements on Stack fn size(&self) -> usize; + /// Returns all data on stack. + fn peek_top(&mut self, no_of_elems: usize) -> &[T]; } struct VecStack { @@ -131,6 +134,11 @@ impl Stack for VecStack { fn size(&self) -> usize { self.stack.len() } + + fn peek_top(&mut self, no_from_top: usize) -> &[S] { + assert!(self.stack.len() >= no_from_top, "peek_top asked for more items than exist."); + &self.stack[self.stack.len() - no_from_top .. self.stack.len()] + } } trait Memory { @@ -293,10 +301,15 @@ impl evm::Evm for Interpreter { while reader.position < code.len() { let instruction = code[reader.position]; - reader.position += 1; // Calculate gas cost let (gas_cost, mem_size) = try!(self.get_gas_cost_mem(ext, instruction, &mut mem, &stack)); + + // TODO: make compile-time removable if too much of a performance hit. + let trace_executed = ext.trace_prepare_execute(reader.position, instruction, &gas_cost); + + reader.position += 1; + try!(self.verify_gas(¤t_gas, &gas_cost)); mem.expand(mem_size); current_gas = current_gas - gas_cost; //TODO: use operator -= @@ -311,10 +324,19 @@ impl evm::Evm for Interpreter { ); }); + let (mem_written, store_written) = match trace_executed { + true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)), + false => (None, None), + }; + // Execute instruction let result = try!(self.exec_instruction( current_gas, ¶ms, ext, instruction, &mut reader, &mut mem, &mut stack - )); + )); + + if trace_executed { + ext.trace_executed(current_gas, stack.peek_top(get_info(instruction).ret), mem_written.map(|(o, s)| (o, &(mem[o..(o + s)]))), store_written); + } // Advance match result { @@ -485,6 +507,31 @@ impl Interpreter { } } + fn mem_written( + instruction: Instruction, + stack: &Stack + ) -> Option<(usize, usize)> { + match instruction { + instructions::MSTORE | instructions::MLOAD => Some((stack.peek(0).low_u64() as usize, 32)), + instructions::MSTORE8 => Some((stack.peek(0).low_u64() as usize, 1)), + instructions::CALLDATACOPY | instructions::CODECOPY => Some((stack.peek(0).low_u64() as usize, stack.peek(2).low_u64() as usize)), + instructions::EXTCODECOPY => Some((stack.peek(1).low_u64() as usize, stack.peek(3).low_u64() as usize)), + instructions::CALL | instructions::CALLCODE => Some((stack.peek(5).low_u64() as usize, stack.peek(6).low_u64() as usize)), + instructions::DELEGATECALL => Some((stack.peek(4).low_u64() as usize, stack.peek(5).low_u64() as usize)), + _ => None, + } + } + + fn store_written( + instruction: Instruction, + stack: &Stack + ) -> Option<(U256, U256)> { + match instruction { + instructions::SSTORE => Some((stack.peek(0).clone(), stack.peek(1).clone())), + _ => None, + } + } + fn mem_gas_cost(&self, schedule: &evm::Schedule, current_mem_size: usize, mem_size: &U256) -> Result<(U256, usize), evm::Error> { let gas_for_mem = |mem_size: U256| { let s = mem_size >> 5; @@ -833,10 +880,12 @@ impl Interpreter { } } - fn verify_instructions_requirements(&self, - info: &instructions::InstructionInfo, - stack_limit: usize, - stack: &Stack) -> Result<(), evm::Error> { + fn verify_instructions_requirements( + &self, + info: &instructions::InstructionInfo, + stack_limit: usize, + stack: &Stack + ) -> Result<(), evm::Error> { if !stack.has(info.args) { Err(evm::Error::StackUnderflow { instruction: info.name, diff --git a/ethcore/src/evm/jit.rs b/ethcore/src/evm/jit.rs index 6a22a1306..694c1668a 100644 --- a/ethcore/src/evm/jit.rs +++ b/ethcore/src/evm/jit.rs @@ -16,6 +16,7 @@ //! Just in time compiler execution environment. use common::*; +use trace::VMTracer; use evmjit; use evm; diff --git a/ethcore/src/evm/mod.rs b/ethcore/src/evm/mod.rs index b7816b99c..06ce5e7e8 100644 --- a/ethcore/src/evm/mod.rs +++ b/ethcore/src/evm/mod.rs @@ -33,3 +33,4 @@ pub use self::evm::{Evm, Error, Result}; pub use self::ext::{Ext, ContractCreateResult, MessageCallResult}; pub use self::factory::{Factory, VMType}; pub use self::schedule::Schedule; +pub use self::instructions::get_info; diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 291b4dba2..7a48e435e 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -21,9 +21,8 @@ use engine::*; use evm::{self, Ext, Factory}; use externalities::*; use substate::*; -use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer}; +use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; 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) @@ -43,6 +42,8 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { pub struct TransactOptions { /// Enable call tracing. pub tracing: bool, + /// Enable VM tracing. + pub vm_tracing: bool, /// Check transaction nonce before execution. pub check_nonce: bool, } @@ -80,21 +81,40 @@ impl<'a> Executive<'a> { } /// Creates `Externalities` from `Executive`. - pub fn as_externalities<'_, T>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_, '_>, tracer: &'_ mut T) -> Externalities<'_, T> where T: Tracer { - Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer) + pub fn as_externalities<'_, T, V>( + &'_ mut self, + origin_info: OriginInfo, + substate: &'_ mut Substate, + output: OutputPolicy<'_, '_>, + tracer: &'_ mut T, + vm_tracer: &'_ mut V + ) -> Externalities<'_, T, V> where T: Tracer, V: VMTracer { + Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer) } /// This function should be used to execute transaction. 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()), - false => self.transact_with_tracer(t, check, NoopTracer), + true => match options.vm_tracing { + true => self.transact_with_tracer(t, check, ExecutiveTracer::default(), ExecutiveVMTracer::default()), + false => self.transact_with_tracer(t, check, ExecutiveTracer::default(), NoopVMTracer), + }, + false => match options.vm_tracing { + true => self.transact_with_tracer(t, check, NoopTracer, ExecutiveVMTracer::default()), + false => self.transact_with_tracer(t, check, NoopTracer, NoopVMTracer), + }, } } /// 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 { + pub fn transact_with_tracer( + &'a mut self, + t: &SignedTransaction, + check_nonce: bool, + mut tracer: T, + mut vm_tracer: V + ) -> Result where T: Tracer, V: VMTracer { let sender = try!(t.sender().map_err(|e| { let message = format!("Transaction malformed: {:?}", e); ExecutionError::TransactionMalformed(message) @@ -154,7 +174,7 @@ impl<'a> Executive<'a> { code: Some(t.data.clone()), data: None, }; - (self.create(params, &mut substate, &mut tracer), vec![]) + (self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![]) }, Action::Call(ref address) => { let params = ActionParams { @@ -170,20 +190,26 @@ impl<'a> Executive<'a> { }; // TODO: move output upstream let mut out = vec![]; - (self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer), out) + (self.call(params, &mut substate, BytesRef::Flexible(&mut out), &mut tracer, &mut vm_tracer), out) } }; // finalize here! - Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop()))) + Ok(try!(self.finalize(t, substate, gas_left, output, tracer.traces().pop(), vm_tracer.drain()))) } - fn exec_vm(&mut self, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, tracer: &mut T) - -> evm::Result where T: Tracer { + fn exec_vm( + &mut self, + params: ActionParams, + unconfirmed_substate: &mut Substate, + output_policy: OutputPolicy, + tracer: &mut T, + vm_tracer: &mut V + ) -> evm::Result where T: Tracer, V: VMTracer { // Ordinary execution - keep VM in same thread if (self.depth + 1) % MAX_VM_DEPTH_FOR_THREAD != 0 { let vm_factory = self.vm_factory; - let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer); + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); return vm_factory.create().exec(params, &mut ext); } @@ -193,7 +219,7 @@ impl<'a> Executive<'a> { // https://github.com/aturon/crossbeam/issues/16 crossbeam::scope(|scope| { let vm_factory = self.vm_factory; - let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer); + let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer); scope.spawn(move || { vm_factory.create().exec(params, &mut ext) @@ -205,8 +231,14 @@ impl<'a> Executive<'a> { /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. - pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef, tracer: &mut T) - -> evm::Result where T: Tracer { + pub fn call( + &mut self, + params: ActionParams, + substate: &mut Substate, + mut output: BytesRef, + tracer: &mut T, + vm_tracer: &mut V + ) -> evm::Result where T: Tracer, V: VMTracer { // backup used in case of running out of gas self.state.snapshot(); @@ -264,16 +296,22 @@ impl<'a> Executive<'a> { let trace_info = tracer.prepare_trace_call(¶ms); let mut trace_output = tracer.prepare_trace_output(); let mut subtracer = tracer.subtracer(); + let gas = params.gas; if params.code.is_some() { // part of substate that may be reverted let mut unconfirmed_substate = Substate::new(); + // TODO: make ActionParams pass by ref then avoid copy altogether. + let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is protected by params.code.is_some condition")); + let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) }; + vm_tracer.done_subtrace(subvmtracer); + trace!(target: "executive", "res={:?}", res); let traces = subtracer.traces(); @@ -307,8 +345,13 @@ impl<'a> Executive<'a> { /// Creates contract with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate. - pub fn create(&mut self, params: ActionParams, substate: &mut Substate, tracer: &mut T) -> evm::Result where T: - Tracer { + pub fn create( + &mut self, + params: ActionParams, + substate: &mut Substate, + tracer: &mut T, + vm_tracer: &mut V + ) -> evm::Result where T: Tracer, V: VMTracer { // backup used in case of running out of gas self.state.snapshot(); @@ -330,10 +373,14 @@ impl<'a> Executive<'a> { let gas = params.gas; let created = params.address.clone(); + let mut subvmtracer = vm_tracer.prepare_subtrace(¶ms.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); + let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer) }; + vm_tracer.done_subtrace(subvmtracer); + match res { Ok(gas_left) => tracer.trace_create( trace_info, @@ -351,7 +398,15 @@ impl<'a> Executive<'a> { } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, t: &SignedTransaction, substate: Substate, result: evm::Result, output: Bytes, trace: Option) -> ExecutionResult { + fn finalize( + &mut self, + t: &SignedTransaction, + substate: Substate, + result: evm::Result, + output: Bytes, + trace: Option, + vm_trace: Option + ) -> ExecutionResult { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero @@ -394,6 +449,7 @@ impl<'a> Executive<'a> { contracts_created: vec![], output: output, trace: trace, + vm_trace: vm_trace, }) }, _ => { @@ -406,6 +462,7 @@ impl<'a> Executive<'a> { contracts_created: substate.contracts_created, output: output, trace: trace, + vm_trace: vm_trace, }) }, } @@ -438,6 +495,7 @@ mod tests { use tests::helpers::*; use trace::trace; use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer}; + use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; #[test] fn test_contract_address() { @@ -466,7 +524,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params, &mut substate, &mut NoopTracer).unwrap() + ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(79_975)); @@ -525,7 +583,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params, &mut substate, &mut NoopTracer).unwrap() + ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -542,7 +600,7 @@ mod tests { // 52 // 60 1d - push 29 // 60 03 - push 3 - // 60 17 - push 17 + // 60 17 - push 23 // f0 - create // 60 00 - push 0 // 55 sstore @@ -578,13 +636,16 @@ mod tests { let engine = TestEngine::new(5); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); + let mut vm_tracer = ExecutiveVMTracer::default(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); let output = BytesRef::Fixed(&mut[0u8;0]); - ex.call(params, &mut substate, output, &mut tracer).unwrap() + ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() }; + assert_eq!(gas_left, U256::from(44_752)); + let expected_trace = vec![ Trace { depth: 0, action: trace::Action::Call(trace::Call { @@ -615,7 +676,39 @@ mod tests { }] }]; assert_eq!(tracer.traces(), expected_trace); - assert_eq!(gas_left, U256::from(44_752)); + + let expected_vm_trace = VMTrace { + parent_step: 0, + code: vec![124, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85, 96, 0, 82, 96, 29, 96, 3, 96, 23, 240, 96, 0, 85], + operations: vec![ + VMOperation { pc: 0, instruction: 124, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vec_into![U256::from_dec_str("2589892687202724018173567190521546555304938078595079151649957320078677").unwrap()], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 30, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 32, instruction: 82, gas_cost: 6.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![0, 0, 0, 96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85] }), store_diff: None }) }, + VMOperation { pc: 33, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99985.into(), stack_push: vec_into![29], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 35, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99982.into(), stack_push: vec_into![3], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 37, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![23], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 39, instruction: 240, gas_cost: 32000.into(), executed: Some(VMExecutedOperation { gas_used: 67979.into(), stack_push: vec_into![U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap()], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 40, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 64752.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 42, instruction: 85, gas_cost: 20000.into(), executed: Some(VMExecutedOperation { gas_used: 44752.into(), stack_push: vec_into![], mem_diff: None, store_diff: Some(StorageDiff { location: 0.into(), value: U256::from_dec_str("1135198453258042933984631383966629874710669425204").unwrap() }) }) } + ], + subs: vec![ + VMTrace { + parent_step: 7, + code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + operations: vec![ + VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67976.into(), stack_push: vec_into![16], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67973.into(), stack_push: vec_into![16, 16], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67970.into(), stack_push: vec_into![12], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67967.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 67958.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) }, + VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 67955.into(), stack_push: vec_into![], mem_diff: None, store_diff: None }) } + ], + subs: vec![] + } + ] + }; + assert_eq!(vm_tracer.drain().unwrap(), expected_vm_trace); } evm_test!{test_create_contract: test_create_contract_jit, test_create_contract_int} @@ -650,12 +743,15 @@ mod tests { let engine = TestEngine::new(5); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); + let mut vm_tracer = ExecutiveVMTracer::default(); let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params.clone(), &mut substate, &mut tracer).unwrap() + ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() }; + assert_eq!(gas_left, U256::from(96_776)); + let expected_trace = vec![Trace { depth: 0, action: trace::Action::Create(trace::Create { @@ -671,9 +767,23 @@ mod tests { }), subs: vec![] }]; - assert_eq!(tracer.traces(), expected_trace); - assert_eq!(gas_left, U256::from(96_776)); + + let expected_vm_trace = VMTrace { + parent_step: 0, + code: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + operations: vec![ + VMOperation { pc: 0, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99997.into(), stack_push: vec_into![16], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 2, instruction: 128, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99994.into(), stack_push: vec_into![16, 16], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 3, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99991.into(), stack_push: vec_into![12], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 5, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99988.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 7, instruction: 57, gas_cost: 9.into(), executed: Some(VMExecutedOperation { gas_used: 99979.into(), stack_push: vec_into![], mem_diff: Some(MemoryDiff { offset: 0, data: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] }), store_diff: None }) }, + VMOperation { pc: 8, instruction: 96, gas_cost: 3.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vec_into![0], mem_diff: None, store_diff: None }) }, + VMOperation { pc: 10, instruction: 243, gas_cost: 0.into(), executed: Some(VMExecutedOperation { gas_used: 99976.into(), stack_push: vec_into![], mem_diff: None, store_diff: None }) } + ], + subs: vec![] + }; + assert_eq!(vm_tracer.drain().unwrap(), expected_vm_trace); } evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int} @@ -722,7 +832,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params, &mut substate, &mut NoopTracer).unwrap() + ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -774,7 +884,7 @@ mod tests { { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params, &mut substate, &mut NoopTracer).unwrap(); + ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap(); } assert_eq!(substate.contracts_created.len(), 1); @@ -835,7 +945,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(73_237)); @@ -880,7 +990,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; assert_eq!(gas_left, U256::from(59_870)); @@ -913,7 +1023,7 @@ mod tests { let executed = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - let opts = TransactOptions { check_nonce: true, tracing: false }; + let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; ex.transact(&t, opts).unwrap() }; @@ -947,7 +1057,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - let opts = TransactOptions { check_nonce: true, tracing: false }; + let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; ex.transact(&t, opts) }; @@ -979,7 +1089,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - let opts = TransactOptions { check_nonce: true, tracing: false }; + let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; ex.transact(&t, opts) }; @@ -1013,7 +1123,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - let opts = TransactOptions { check_nonce: true, tracing: false }; + let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; ex.transact(&t, opts) }; @@ -1047,7 +1157,7 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - let opts = TransactOptions { check_nonce: true, tracing: false }; + let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; ex.transact(&t, opts) }; @@ -1082,7 +1192,7 @@ mod tests { let result = { let mut ex = Executive::new(&mut state, &info, &engine, &factory); - ex.create(params, &mut substate, &mut NoopTracer) + ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) }; match result { diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 99d2eed72..675d1904b 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -21,7 +21,7 @@ use engine::*; use executive::*; use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory}; use substate::*; -use trace::Tracer; +use trace::{Tracer, VMTracer}; /// Policy for handling output data on `RETURN` opcode. pub enum OutputPolicy<'a, 'b> { @@ -55,7 +55,7 @@ impl OriginInfo { } /// Implementation of evm Externalities. -pub struct Externalities<'a, T> where T: 'a + Tracer { +pub struct Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { state: &'a mut State, env_info: &'a EnvInfo, engine: &'a Engine, @@ -66,10 +66,10 @@ pub struct Externalities<'a, T> where T: 'a + Tracer { schedule: Schedule, output: OutputPolicy<'a, 'a>, tracer: &'a mut T, + vm_tracer: &'a mut V, } -impl<'a, T> Externalities<'a, T> where T: 'a + Tracer { - +impl<'a, T, V> Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { #[cfg_attr(feature="dev", allow(too_many_arguments))] /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, @@ -81,6 +81,7 @@ impl<'a, T> Externalities<'a, T> where T: 'a + Tracer { substate: &'a mut Substate, output: OutputPolicy<'a, 'a>, tracer: &'a mut T, + vm_tracer: &'a mut V, ) -> Self { Externalities { state: state, @@ -93,11 +94,12 @@ impl<'a, T> Externalities<'a, T> where T: 'a + Tracer { schedule: engine.schedule(env_info), output: output, tracer: tracer, + vm_tracer: vm_tracer, } } } -impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer { +impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { fn storage_at(&self, key: &H256) -> H256 { self.state.storage_at(&self.origin_info.address, key) } @@ -152,7 +154,7 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer { let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth); // TODO: handle internal error separately - match ex.create(params, self.substate, self.tracer) { + match ex.create(params, self.substate, self.tracer, self.vm_tracer) { Ok(gas_left) => { self.substate.contracts_created.push(address.clone()); ContractCreateResult::Created(address, gas_left) @@ -190,7 +192,7 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer { let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth); - match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer) { + match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { Ok(gas_left) => MessageCallResult::Success(gas_left), _ => MessageCallResult::Failed } @@ -286,6 +288,14 @@ impl<'a, T> Ext for Externalities<'a, T> where T: 'a + Tracer { fn inc_sstore_clears(&mut self) { self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one(); } + + fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool { + self.vm_tracer.trace_prepare_execute(pc, instruction, gas_cost) + } + + fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) { + self.vm_tracer.trace_executed(gas_used, stack_push, mem_diff, store_diff) + } } #[cfg(test)] @@ -297,7 +307,7 @@ mod tests { use substate::*; use tests::helpers::*; use super::*; - use trace::{NoopTracer}; + use trace::{NoopTracer, NoopVMTracer}; fn get_test_origin() -> OriginInfo { OriginInfo { @@ -349,9 +359,10 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; let vm_factory = Default::default(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); assert_eq!(ext.env_info().number, 100); } @@ -361,9 +372,10 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; let vm_factory = Default::default(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -383,9 +395,10 @@ mod tests { } let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; let vm_factory = Default::default(); - let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); @@ -398,9 +411,10 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; let vm_factory = Default::default(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut output = vec![]; @@ -423,10 +437,11 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; { let vm_factory = Default::default(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); ext.log(log_topics, &log_data); } @@ -440,10 +455,11 @@ mod tests { let mut setup = TestSetup::new(); let state = setup.state.reference_mut(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; { let vm_factory = Default::default(); - let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer); + let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); ext.suicide(&refund_account); } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 9e9620169..c5d781ab2 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -25,6 +25,7 @@ use substate::*; use tests::helpers::*; use ethjson; use trace::{Tracer, NoopTracer}; +use trace::{VMTracer, NoopVMTracer}; #[derive(Debug, PartialEq)] struct CallCreate { @@ -48,32 +49,35 @@ impl From for CallCreate { /// Tiny wrapper around executive externalities. /// Stores callcreates. -struct TestExt<'a, T> where T: 'a + Tracer { - ext: Externalities<'a, T>, +struct TestExt<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { + ext: Externalities<'a, T, V>, callcreates: Vec, contract_address: Address } -impl<'a, T> TestExt<'a, T> where T: 'a + Tracer { - fn new(state: &'a mut State, - info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - output: OutputPolicy<'a, 'a>, - address: Address, - tracer: &'a mut T) -> Self { +impl<'a, T, V> TestExt<'a, T, V> where T: 'a + Tracer, V: 'a + VMTracer { + fn new( + state: &'a mut State, + info: &'a EnvInfo, + engine: &'a Engine, + vm_factory: &'a Factory, + depth: usize, + origin_info: OriginInfo, + substate: &'a mut Substate, + output: OutputPolicy<'a, 'a>, + address: Address, + tracer: &'a mut T, + vm_tracer: &'a mut V, + ) -> Self { TestExt { contract_address: contract_address(&address, &state.nonce(&address)), - ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer), + ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer), callcreates: vec![] } } } -impl<'a, T> Ext for TestExt<'a, T> where T: Tracer { +impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer { fn storage_at(&self, key: &H256) -> H256 { self.ext.storage_at(key) } @@ -186,6 +190,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { let mut substate = Substate::new(); let mut tracer = NoopTracer; + let mut vm_tracer = NoopVMTracer; let mut output = vec![]; // execute @@ -201,6 +206,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { OutputPolicy::Return(BytesRef::Flexible(&mut output), None), params.address.clone(), &mut tracer, + &mut vm_tracer, ); let evm = vm_factory.create(); let res = evm.exec(params, &mut ex); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 5cf9d50a1..cb7942f23 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -141,3 +141,5 @@ mod tests; mod json_tests; pub use types::*; +pub use evm::get_info; +pub use executive::contract_address; \ No newline at end of file diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 66b17cd7c..46b5ae733 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -251,7 +251,7 @@ impl MinerService for Miner { } } - fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction) -> Result { + fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, vm_tracing: bool) -> Result { let sealing_work = self.sealing_work.lock().unwrap(); match sealing_work.peek_last_ref() { Some(work) => { @@ -277,12 +277,13 @@ impl MinerService for Miner { // give the sender max balance state.sub_balance(&sender, &balance); state.add_balance(&sender, &U256::max_value()); - let options = TransactOptions { tracing: false, check_nonce: false }; + let options = TransactOptions { tracing: false, vm_tracing: vm_tracing, check_nonce: false }; + // TODO: use vm_trace here. Executive::new(&mut state, &env_info, self.engine(), chain.vm_factory()).transact(t, options) }, None => { - chain.call(t) + chain.call(t, vm_tracing) } } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 60b680f7a..8165dfbba 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -148,7 +148,7 @@ pub trait MinerService : Send + Sync { fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> U256; /// Call into contract code using pending state. - fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction) -> Result; + fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, vm_tracing: bool) -> Result; /// Get storage value in pending state. fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> H256; diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index c099b17a5..51162bb8e 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -183,16 +183,14 @@ impl State { /// Add `incr` to the balance of account `a`. pub fn add_balance(&mut self, a: &Address, incr: &U256) { - let old = self.balance(a); + trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)); self.require(a, false).add_balance(incr); - trace!("state: add_balance({}, {}): {} -> {}\n", a, incr, old, self.balance(a)); } /// Subtract `decr` from the balance of account `a`. pub fn sub_balance(&mut self, a: &Address, decr: &U256) { - let old = self.balance(a); + trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a)); self.require(a, false).sub_balance(decr); - trace!("state: sub_balance({}, {}): {} -> {}\n", a, decr, old, self.balance(a)); } /// Subtracts `by` from the balance of `from` and adds it to that of `to`. @@ -222,7 +220,7 @@ impl State { pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, vm_factory: &EvmFactory, t: &SignedTransaction, tracing: bool) -> ApplyResult { // let old = self.to_pod(); - let options = TransactOptions { tracing: tracing, check_nonce: true }; + let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true }; let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options)); // TODO uncomment once to_pod() works correctly. diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs index a0bff1c72..a1a13cf43 100644 --- a/ethcore/src/trace/executive_tracer.rs +++ b/ethcore/src/trace/executive_tracer.rs @@ -18,13 +18,13 @@ use util::{Bytes, Address, U256}; use action_params::ActionParams; -use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult}; -use trace::Tracer; +use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff}; +use trace::{Tracer, VMTracer}; /// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls. #[derive(Default)] pub struct ExecutiveTracer { - traces: Vec + traces: Vec, } impl Tracer for ExecutiveTracer { @@ -40,8 +40,7 @@ impl Tracer for ExecutiveTracer { Some(vec![]) } - fn trace_call(&mut self, call: Option, gas_used: U256, output: Option, depth: usize, subs: - Vec, delegate_call: bool) { + fn trace_call(&mut self, call: Option, gas_used: U256, output: Option, depth: usize, subs: Vec, delegate_call: bool) { // don't trace if it's DELEGATECALL or CALLCODE. if delegate_call { return; @@ -106,3 +105,46 @@ impl Tracer for ExecutiveTracer { self.traces } } + +/// Simple VM tracer. Traces all operations. +#[derive(Default)] +pub struct ExecutiveVMTracer { + data: VMTrace, +} + +impl VMTracer for ExecutiveVMTracer { + fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool { + self.data.operations.push(VMOperation { + pc: pc, + instruction: instruction, + gas_cost: gas_cost.clone(), + executed: None, + }); + true + } + + fn trace_executed(&mut self, gas_used: U256, stack_push: &[U256], mem_diff: Option<(usize, &[u8])>, store_diff: Option<(U256, U256)>) { + let ex = VMExecutedOperation { + gas_used: gas_used, + stack_push: stack_push.iter().cloned().collect(), + mem_diff: mem_diff.map(|(s, r)| MemoryDiff{ offset: s, data: r.iter().cloned().collect() }), + store_diff: store_diff.map(|(l, v)| StorageDiff{ location: l, value: v }), + }; + self.data.operations.last_mut().expect("trace_executed is always called after a trace_prepare_execute").executed = Some(ex); + } + + fn prepare_subtrace(&self, code: &Bytes) -> Self { + ExecutiveVMTracer { data: VMTrace { + parent_step: self.data.operations.len(), + code: code.clone(), + operations: vec![], + subs: vec![], + }} + } + + fn done_subtrace(&mut self, sub: Self) { + self.data.subs.push(sub.data); + } + + fn drain(mut self) -> Option { self.data.subs.pop() } +} diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index f51cf8ee5..53c062137 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -31,9 +31,9 @@ pub use self::block::BlockTraces; pub use self::config::{Config, Switch}; pub use self::db::TraceDB; pub use self::error::Error; -pub use types::trace_types::trace::Trace; -pub use self::noop_tracer::NoopTracer; -pub use self::executive_tracer::ExecutiveTracer; +pub use types::trace_types::trace::{Trace, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff}; +pub use self::noop_tracer::{NoopTracer, NoopVMTracer}; +pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer}; pub use types::trace_types::filter::{Filter, AddressesFilter}; pub use self::import::ImportRequest; pub use self::localized::LocalizedTrace; @@ -81,13 +81,32 @@ pub trait Tracer: Send { /// Stores failed create trace. fn trace_failed_create(&mut self, create: Option, depth: usize, subs: Vec); - /// Spawn subracer which will be used to trace deeper levels of execution. + /// Spawn subtracer which will be used to trace deeper levels of execution. fn subtracer(&self) -> Self where Self: Sized; /// Consumes self and returns all traces. fn traces(self) -> Vec; } +/// Used by executive to build VM traces. +pub trait VMTracer: Send { + /// Trace the preparation to execute a single instruction. + /// @returns true if `trace_executed` should be called. + fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false } + + /// Trace the finalised execution of a single instruction. + fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {} + + /// Spawn subtracer which will be used to trace deeper levels of execution. + fn prepare_subtrace(&self, code: &Bytes) -> Self where Self: Sized; + + /// Spawn subtracer which will be used to trace deeper levels of execution. + fn done_subtrace(&mut self, sub: Self) where Self: Sized; + + /// Consumes self and returns the VM trace. + fn drain(self) -> Option; +} + /// `DbExtras` provides an interface to query extra data which is not stored in tracesdb, /// but necessary to work correctly. pub trait DatabaseExtras { diff --git a/ethcore/src/trace/noop_tracer.rs b/ethcore/src/trace/noop_tracer.rs index 2581e692b..ed0231b79 100644 --- a/ethcore/src/trace/noop_tracer.rs +++ b/ethcore/src/trace/noop_tracer.rs @@ -18,8 +18,8 @@ use util::{Bytes, Address, U256}; use action_params::ActionParams; -use trace::Tracer; -use trace::trace::{Trace, Call, Create}; +use trace::{Tracer, VMTracer}; +use trace::trace::{Trace, Call, Create, VMTrace}; /// Nonoperative tracer. Does not trace anything. pub struct NoopTracer; @@ -63,3 +63,23 @@ impl Tracer for NoopTracer { vec![] } } + +/// Nonoperative VM tracer. Does not trace anything. +pub struct NoopVMTracer; + +impl VMTracer for NoopVMTracer { + /// Trace the preparation to execute a single instruction. + fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { false } + + /// Trace the finalised execution of a single instruction. + fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {} + + /// Spawn subtracer which will be used to trace deeper levels of execution. + fn prepare_subtrace(&self, _code: &Bytes) -> Self { NoopVMTracer } + + /// Spawn subtracer which will be used to trace deeper levels of execution. + fn done_subtrace(&mut self, _sub: Self) {} + + /// Consumes self and returns all VM traces. + fn drain(self) -> Option { None } +} diff --git a/ethcore/src/types/executed.rs b/ethcore/src/types/executed.rs index fcde5a392..823c9dda1 100644 --- a/ethcore/src/types/executed.rs +++ b/ethcore/src/types/executed.rs @@ -18,7 +18,7 @@ use util::numbers::*; use util::Bytes; -use trace::Trace; +use trace::{Trace, VMTrace}; use types::log_entry::LogEntry; use ipc::binary::BinaryConvertError; use std::fmt; @@ -59,6 +59,8 @@ pub struct Executed { pub output: Bytes, /// The trace of this transaction. pub trace: Option, + /// The VM trace of this transaction. + pub vm_trace: Option, } /// Result of executing the transaction. diff --git a/ethcore/src/types/trace_types/trace.rs b/ethcore/src/types/trace_types/trace.rs index f8fe07360..243acaf64 100644 --- a/ethcore/src/types/trace_types/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -349,6 +349,170 @@ impl Trace { } } +#[derive(Debug, Clone, PartialEq, Binary)] +/// A diff of some chunk of memory. +pub struct MemoryDiff { + /// Offset into memory the change begins. + pub offset: usize, + /// The changed data. + pub data: Bytes, +} + +impl Encodable for MemoryDiff { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.offset); + s.append(&self.data); + } +} + +impl Decodable for MemoryDiff { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + Ok(MemoryDiff { + offset: try!(d.val_at(0)), + data: try!(d.val_at(1)), + }) + } +} + +#[derive(Debug, Clone, PartialEq, Binary)] +/// A diff of some storage value. +pub struct StorageDiff { + /// Which key in storage is changed. + pub location: U256, + /// What the value has been changed to. + pub value: U256, +} + +impl Encodable for StorageDiff { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.location); + s.append(&self.value); + } +} + +impl Decodable for StorageDiff { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + Ok(StorageDiff { + location: try!(d.val_at(0)), + value: try!(d.val_at(1)), + }) + } +} + +#[derive(Debug, Clone, PartialEq, Binary)] +/// A record of an executed VM operation. +pub struct VMExecutedOperation { + /// The total gas used. + pub gas_used: U256, + /// The stack item placed, if any. + pub stack_push: Vec, + /// If altered, the memory delta. + pub mem_diff: Option, + /// The altered storage value, if any. + pub store_diff: Option, +} + +impl Encodable for VMExecutedOperation { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(4); + s.append(&self.gas_used); + s.append(&self.stack_push); + s.append(&self.mem_diff); + s.append(&self.store_diff); + } +} + +impl Decodable for VMExecutedOperation { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + Ok(VMExecutedOperation { + gas_used: try!(d.val_at(0)), + stack_push: try!(d.val_at(1)), + mem_diff: try!(d.val_at(2)), + store_diff: try!(d.val_at(3)), + }) + } +} + +#[derive(Debug, Clone, PartialEq, Binary)] +/// A record of the execution of a single VM operation. +pub struct VMOperation { + /// The program counter. + pub pc: usize, + /// The instruction executed. + pub instruction: u8, + /// The gas cost for this instruction. + pub gas_cost: U256, + /// Information concerning the execution of the operation. + pub executed: Option, +} + +impl Encodable for VMOperation { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(4); + s.append(&self.pc); + s.append(&self.instruction); + s.append(&self.gas_cost); + s.append(&self.executed); + } +} + +impl Decodable for VMOperation { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let res = VMOperation { + pc: try!(d.val_at(0)), + instruction: try!(d.val_at(1)), + gas_cost: try!(d.val_at(2)), + executed: try!(d.val_at(3)), + }; + + Ok(res) + } +} + +#[derive(Debug, Clone, PartialEq, Binary, Default)] +/// A record of a full VM trace for a CALL/CREATE. +pub struct VMTrace { + /// The step (i.e. index into operations) at which this trace corresponds. + pub parent_step: usize, + /// The code to be executed. + pub code: Bytes, + /// The operations executed. + pub operations: Vec, + /// The sub traces for each interior action performed as part of this call/create. + /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. + pub subs: Vec, +} + +impl Encodable for VMTrace { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(4); + s.append(&self.parent_step); + s.append(&self.code); + s.append(&self.operations); + s.append(&self.subs); + } +} + +impl Decodable for VMTrace { + fn decode(decoder: &D) -> Result where D: Decoder { + let d = decoder.as_rlp(); + let res = VMTrace { + parent_step: try!(d.val_at(0)), + code: try!(d.val_at(1)), + operations: try!(d.val_at(2)), + subs: try!(d.val_at(3)), + }; + + Ok(res) + } +} + #[cfg(test)] mod tests { use util::{Address, U256, FixedHash}; diff --git a/json/src/state/transaction.rs b/json/src/state/transaction.rs index 15626c224..62b8577d4 100644 --- a/json/src/state/transaction.rs +++ b/json/src/state/transaction.rs @@ -40,7 +40,7 @@ pub struct Transaction { /// To. pub to: MaybeEmpty
, /// Value. - pub value: Uint + pub value: Uint, } #[cfg(test)] diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index d9f0cd4eb..143d6b48f 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -153,7 +153,7 @@ pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet } }, Api::Ethcore => { - server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) + server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) }, Api::Traces => { server.add_delegate(TracesClient::new(&deps.client).to_delegate()) diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index ab5069334..b46a13197 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -26,6 +26,7 @@ extern crate serde; extern crate serde_json; extern crate jsonrpc_core; extern crate jsonrpc_http_server; +#[macro_use] extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 83a788599..49cbafe27 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -511,8 +511,8 @@ impl Eth for EthClient where .and_then(|(request, block_number,)| { let signed = try!(self.sign_call(request)); let r = match block_number { - BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed), - BlockNumber::Latest => take_weak!(self.client).call(&signed), + BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, false), + BlockNumber::Latest => take_weak!(self.client).call(&signed, false), _ => panic!("{:?}", block_number), }; to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![]))) @@ -524,8 +524,8 @@ impl Eth for EthClient where .and_then(|(request, block_number,)| { let signed = try!(self.sign_call(request)); let r = match block_number { - BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed), - BlockNumber::Latest => take_weak!(self.client).call(&signed), + BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, false), + BlockNumber::Latest => take_weak!(self.client).call(&signed, false), _ => return Err(Error::invalid_params()), }; to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))) diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index e649e37f4..ca14ca021 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Ethcore-specific rpc implementation. -use util::{U256, Address, RotatingLogger}; +use util::{U256, Address, RotatingLogger, FixedHash, Uint}; use util::network_settings::NetworkSettings; use util::misc::version_data; use std::sync::{Arc, Weak}; @@ -23,29 +23,99 @@ use std::ops::Deref; use std::collections::BTreeMap; use jsonrpc_core::*; use ethcore::miner::MinerService; +use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; +use ethcore::client::BlockChainClient; +use ethcore::trace::VMTrace; use v1::traits::Ethcore; -use v1::types::Bytes; +use v1::types::{Bytes, CallRequest}; /// Ethcore implementation. -pub struct EthcoreClient - where M: MinerService { +pub struct EthcoreClient where + C: BlockChainClient, + M: MinerService { + + client: Weak, miner: Weak, logger: Arc, settings: Arc, } -impl EthcoreClient where M: MinerService { +impl EthcoreClient where C: BlockChainClient, M: MinerService { /// Creates new `EthcoreClient`. - pub fn new(miner: &Arc, logger: Arc, settings: Arc) -> Self { + pub fn new(client: &Arc, miner: &Arc, logger: Arc, settings: Arc) -> Self { EthcoreClient { + client: Arc::downgrade(client), miner: Arc::downgrade(miner), logger: logger, settings: settings, } } + + // TODO: share with eth.rs + fn sign_call(&self, request: CallRequest) -> Result { + let client = take_weak!(self.client); + let miner = take_weak!(self.miner); + let from = request.from.unwrap_or(Address::zero()); + Ok(EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.latest_nonce(&from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or(U256::from(50_000_000)), + gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }.fake_sign(from)) + } } -impl Ethcore for EthcoreClient where M: MinerService + 'static { +fn vm_trace_to_object(t: &VMTrace) -> Value { + let mut ret = BTreeMap::new(); + ret.insert("code".to_owned(), to_value(&t.code).unwrap()); + + let mut subs = t.subs.iter(); + let mut next_sub = subs.next(); + + let ops = t.operations + .iter() + .enumerate() + .map(|(i, op)| { + let mut m = map![ + "pc".to_owned() => to_value(&op.pc).unwrap(), + "cost".to_owned() => match op.gas_cost <= U256::from(!0u64) { + true => to_value(&op.gas_cost.low_u64()), + false => to_value(&op.gas_cost), + }.unwrap() + ]; + if let Some(ref ex) = op.executed { + let mut em = map![ + "used".to_owned() => to_value(&ex.gas_used.low_u64()).unwrap(), + "push".to_owned() => to_value(&ex.stack_push).unwrap() + ]; + if let Some(ref md) = ex.mem_diff { + em.insert("mem".to_owned(), Value::Object(map![ + "off".to_owned() => to_value(&md.offset).unwrap(), + "data".to_owned() => to_value(&md.data).unwrap() + ])); + } + if let Some(ref sd) = ex.store_diff { + em.insert("store".to_owned(), Value::Object(map![ + "key".to_owned() => to_value(&sd.location).unwrap(), + "val".to_owned() => to_value(&sd.value).unwrap() + ])); + } + m.insert("ex".to_owned(), Value::Object(em)); + } + if next_sub.is_some() && next_sub.unwrap().parent_step == i { + m.insert("sub".to_owned(), vm_trace_to_object(next_sub.unwrap())); + next_sub = subs.next(); + } + Value::Object(m) + }) + .collect::>(); + ret.insert("ops".to_owned(), Value::Array(ops)); + Value::Object(ret) +} + +impl Ethcore for EthcoreClient where C: BlockChainClient + 'static, M: MinerService + 'static { fn set_min_gas_price(&self, params: Params) -> Result { from_params::<(U256,)>(params).and_then(|(gas_price,)| { @@ -135,4 +205,19 @@ impl Ethcore for EthcoreClient where M: MinerService + 'static { let version = version_data(); to_value(&Bytes::new(version)) } + + fn vm_trace_call(&self, params: Params) -> Result { + trace!(target: "jsonrpc", "vm_trace_call: {:?}", params); + from_params(params) + .and_then(|(request,)| { + let signed = try!(self.sign_call(request)); + let r = take_weak!(self.client).call(&signed, true); + if let Ok(executed) = r { + if let Some(vm_trace) = executed.vm_trace { + return Ok(vm_trace_to_object(&vm_trace)); + } + } + Ok(Value::Null) + }) + } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 93887fb63..a7f7920ad 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -19,13 +19,12 @@ use std::collections::HashMap; use std::sync::Arc; use std::str::FromStr; -use ethcore::client::{MiningBlockChainClient, BlockChainClient, Client, ClientConfig}; +use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::ids::BlockID; use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; use ethcore::ethereum; -use ethcore::transaction::{Transaction, Action}; use ethcore::miner::{MinerService, ExternalMiner, Miner}; use devtools::RandomTempPath; use util::Hashable; diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index a53ca3a08..0f9327887 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -202,7 +202,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: &MiningBlockChainClient, _t: &SignedTransaction) -> Result { + fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _vm_tracing: bool) -> Result { unimplemented!(); } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 63e66f797..4f43be827 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -365,7 +365,7 @@ fn rpc_eth_pending_transaction_by_hash() { tester.miner.pending_transactions.lock().unwrap().insert(H256::zero(), tx); } - let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x01","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x00","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x01","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x00","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#; let request = r#"{ "jsonrpc": "2.0", "method": "eth_getTransactionByHash", @@ -430,6 +430,7 @@ fn rpc_eth_call() { contracts_created: vec![], output: vec![0x12, 0x34, 0xff], trace: None, + vm_trace: None, }); let request = r#"{ @@ -463,6 +464,7 @@ fn rpc_eth_call_default_block() { contracts_created: vec![], output: vec![0x12, 0x34, 0xff], trace: None, + vm_trace: None, }); let request = r#"{ @@ -495,6 +497,7 @@ fn rpc_eth_estimate_gas() { contracts_created: vec![], output: vec![0x12, 0x34, 0xff], trace: None, + vm_trace: None, }); let request = r#"{ @@ -528,6 +531,7 @@ fn rpc_eth_estimate_gas_default_block() { contracts_created: vec![], output: vec![0x12, 0x34, 0xff], trace: None, + vm_trace: None, }); let request = r#"{ diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index d51545d86..3bed1f0f0 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use std::str::FromStr; use jsonrpc_core::IoHandler; use v1::{Ethcore, EthcoreClient}; +use ethcore::client::{TestBlockChainClient}; use ethcore::miner::MinerService; use v1::tests::helpers::TestMinerService; use util::numbers::*; @@ -25,10 +26,15 @@ use rustc_serialize::hex::FromHex; use util::log::RotatingLogger; use util::network_settings::NetworkSettings; +fn blockchain_client() -> Arc { + let client = TestBlockChainClient::new(); + Arc::new(client) +} fn miner_service() -> Arc { Arc::new(TestMinerService::default()) } + fn logger() -> Arc { Arc::new(RotatingLogger::new("rpc=trace".to_owned())) } @@ -45,14 +51,15 @@ fn settings() -> Arc { }) } -fn ethcore_client(miner: &Arc) -> EthcoreClient { - EthcoreClient::new(&miner, logger(), settings()) +fn ethcore_client(client: &Arc, miner: &Arc) -> EthcoreClient { + EthcoreClient::new(&client, &miner, logger(), settings()) } #[test] fn rpc_ethcore_extra_data() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -68,7 +75,8 @@ fn rpc_ethcore_default_extra_data() { use util::ToPretty; let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -81,7 +89,8 @@ fn rpc_ethcore_default_extra_data() { #[test] fn rpc_ethcore_gas_floor_target() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -94,7 +103,8 @@ fn rpc_ethcore_gas_floor_target() { #[test] fn rpc_ethcore_min_gas_price() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -107,7 +117,8 @@ fn rpc_ethcore_min_gas_price() { #[test] fn rpc_ethcore_set_min_gas_price() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -121,7 +132,8 @@ fn rpc_ethcore_set_min_gas_price() { #[test] fn rpc_ethcore_set_gas_floor_target() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -135,7 +147,8 @@ fn rpc_ethcore_set_gas_floor_target() { #[test] fn rpc_ethcore_set_extra_data() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -149,7 +162,8 @@ fn rpc_ethcore_set_extra_data() { #[test] fn rpc_ethcore_set_author() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -163,10 +177,11 @@ fn rpc_ethcore_set_author() { #[test] fn rpc_ethcore_dev_logs() { let miner = miner_service(); + let client = blockchain_client(); let logger = logger(); logger.append("a".to_owned()); logger.append("b".to_owned()); - let ethcore = EthcoreClient::new(&miner, logger.clone(), settings()).to_delegate(); + let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings()).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -179,7 +194,8 @@ fn rpc_ethcore_dev_logs() { #[test] fn rpc_ethcore_dev_logs_levels() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -191,7 +207,8 @@ fn rpc_ethcore_dev_logs_levels() { #[test] fn rpc_ethcore_set_transactions_limit() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -205,7 +222,8 @@ fn rpc_ethcore_set_transactions_limit() { #[test] fn rpc_ethcore_transactions_limit() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -218,7 +236,8 @@ fn rpc_ethcore_transactions_limit() { #[test] fn rpc_ethcore_net_chain() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -231,7 +250,8 @@ fn rpc_ethcore_net_chain() { #[test] fn rpc_ethcore_net_max_peers() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -244,7 +264,8 @@ fn rpc_ethcore_net_max_peers() { #[test] fn rpc_ethcore_net_port() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -257,7 +278,8 @@ fn rpc_ethcore_net_port() { #[test] fn rpc_ethcore_rpc_settings() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -270,7 +292,8 @@ fn rpc_ethcore_rpc_settings() { #[test] fn rpc_ethcore_node_name() { let miner = miner_service(); - let ethcore = ethcore_client(&miner).to_delegate(); + let client = blockchain_client(); + let ethcore = ethcore_client(&client, &miner).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 3646f6c5a..abc87bbb8 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -72,6 +72,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns default extra data fn default_extra_data(&self, _: Params) -> Result; + /// Executes the given call and returns the VM trace for it. + fn vm_trace_call(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { @@ -95,6 +97,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static { delegate.add_method("ethcore_nodeName", Ethcore::node_name); delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data); + delegate.add_method("ethcore_vmTraceCall", Ethcore::vm_trace_call); + delegate } } diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 5810c85e5..b86723357 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -103,7 +103,7 @@ mod tests { fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x","creates":null}]"#); let t = BlockTransactions::Hashes(vec![H256::default()]); let serialized = serde_json::to_string(&t).unwrap(); diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 1c9a41084..6a9f0e590 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use util::numbers::*; +use ethcore::contract_address; use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction}; use v1::types::{Bytes, OptionalValue}; @@ -46,7 +47,9 @@ pub struct Transaction { /// Gas pub gas: U256, /// Data - pub input: Bytes + pub input: Bytes, + /// Creates contract + pub creates: OptionalValue
, } impl From for Transaction { @@ -65,7 +68,11 @@ impl From for Transaction { value: t.value, gas_price: t.gas_price, gas: t.gas, - input: Bytes::new(t.data.clone()) + input: Bytes::new(t.data.clone()), + creates: match t.action { + Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)), + Action::Call(_) => OptionalValue::Null, + }, } } } @@ -86,7 +93,11 @@ impl From for Transaction { value: t.value, gas_price: t.gas_price, gas: t.gas, - input: Bytes::new(t.data.clone()) + input: Bytes::new(t.data.clone()), + creates: match t.action { + Action::Create => OptionalValue::Value(contract_address(&t.sender().unwrap(), &t.nonce)), + Action::Call(_) => OptionalValue::Null, + }, } } } @@ -100,7 +111,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x","creates":null}"#); } } diff --git a/util/src/common.rs b/util/src/common.rs index 0e0cd7757..941b5b0a6 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -24,6 +24,13 @@ pub use vector::*; pub use numbers::*; pub use sha3::*; +#[macro_export] +macro_rules! vec_into { + ( $( $x:expr ),* ) => { + vec![ $( $x.into() ),* ] + } +} + #[macro_export] macro_rules! hash_map { () => { HashMap::new() }; diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index c2ff88c41..5da3a3822 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -338,6 +338,18 @@ impl Encodable for Vec where T: Encodable { } } +impl Encodable for Option where T: Encodable { + fn rlp_append(&self, s: &mut RlpStream) { + match *self { + None => { s.begin_list(0); }, + Some(ref x) => { + s.begin_list(1); + s.append_internal(x); + } + } + } +} + impl RlpEncodable for T where T: Encodable { fn rlp_append(&self, s: &mut RlpStream) { Encodable::rlp_append(self, s) diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 1aa688aba..6109a643b 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -395,7 +395,7 @@ impl<'a> Decoder for BasicDecoder<'a> { } impl Decodable for T where T: FromBytes { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { decoder.read_value(| bytes | { Ok(try!(T::from_bytes(bytes))) }) @@ -403,13 +403,19 @@ impl Decodable for T where T: FromBytes { } impl Decodable for Vec where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect() } } +impl Decodable for Option where T: Decodable { + fn decode(decoder: &D) -> Result where D: Decoder { + decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect::, DecoderError>>().map(|mut a| a.pop()) + } +} + impl Decodable for Vec { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { decoder.read_value(| bytes | { let mut res = vec![]; res.extend_from_slice(bytes); @@ -418,22 +424,10 @@ impl Decodable for Vec { } } -impl Decodable for Option where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { - decoder.read_value(| bytes | { - let res = match bytes.len() { - 0 => None, - _ => Some(try!(T::decode(decoder))) - }; - Ok(res) - }) - } -} - macro_rules! impl_array_decodable { ($index_type:ty, $len:expr ) => ( impl Decodable for [T; $len] where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { let decoders = decoder.as_rlp(); let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() }; @@ -466,7 +460,7 @@ impl_array_decodable_recursive!( ); impl RlpDecodable for T where T: Decodable { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { Decodable::decode(decoder) } } @@ -489,7 +483,7 @@ impl FromBytes for DecodableU8 { } impl RlpDecodable for u8 { - fn decode(decoder: &D) -> Result where D: Decoder { + fn decode(decoder: &D) -> Result where D: Decoder { let u: DecodableU8 = try!(Decodable::decode(decoder)); Ok(u.0) }