From efa8f661e558d77fa3f0f3f528f3718c84abf474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 15 Jun 2016 00:17:23 +0200 Subject: [PATCH 01/17] More meaningful errors when sending transaction --- Cargo.lock | 42 +++++++++++----------- rpc/src/v1/helpers/signing_queue.rs | 30 +++++++++------- rpc/src/v1/impls/eth_signing.rs | 22 ++++++++---- rpc/src/v1/impls/mod.rs | 55 +++++++++++++++++++++++++++-- rpc/src/v1/impls/personal_signer.rs | 6 ++-- 5 files changed, 109 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c850940c9..5b8be3cc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -233,7 +233,7 @@ dependencies = [ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -279,7 +279,7 @@ dependencies = [ "ethcore-rpc 1.2.0", "ethcore-util 1.2.0", "hyper 0.9.3 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -290,8 +290,8 @@ dependencies = [ "parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)", "parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -330,7 +330,7 @@ name = "ethcore-ipc-nano" version = "1.2.0" dependencies = [ "ethcore-ipc 1.2.0", - "jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (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.1 (git+https://github.com/ethcore/nanomsg.rs.git)", ] @@ -347,12 +347,12 @@ dependencies = [ "ethjson 0.1.0", "ethsync 1.2.0", "json-ipc-server 0.2.2 (git+https://github.com/ethcore/json-ipc-server.git)", - "jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -366,7 +366,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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-minimal-sysui 0.1.0 (git+https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -401,7 +401,7 @@ dependencies = [ "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)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -416,8 +416,8 @@ version = "0.1.0" dependencies = [ "ethcore-util 1.2.0", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -575,7 +575,7 @@ source = "git+https://github.com/ethcore/json-ipc-server.git#15ef25e5f859d2d2746 dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -593,11 +593,11 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "2.0.5" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -608,7 +608,7 @@ version = "5.1.0" source = "git+https://github.com/ethcore/jsonrpc-http-server.git#6117b1d77b5a60d6fa2dc884f12aa7f5fd4585ca" dependencies = [ "hyper 0.9.3 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1185,12 +1185,12 @@ dependencies = [ [[package]] name = "serde" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_codegen" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1206,7 +1206,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/rpc/src/v1/helpers/signing_queue.rs b/rpc/src/v1/helpers/signing_queue.rs index 0ded8998c..dd59ce967 100644 --- a/rpc/src/v1/helpers/signing_queue.rs +++ b/rpc/src/v1/helpers/signing_queue.rs @@ -19,8 +19,11 @@ use std::time::{Instant, Duration}; use std::sync::{mpsc, Mutex, RwLock, Arc}; use std::collections::HashMap; use v1::types::{TransactionRequest, TransactionConfirmation}; -use util::{U256, H256}; +use util::U256; +use jsonrpc_core; +/// Result that can be returned from JSON RPC. +pub type RpcResult = Result; /// Possible events happening in the queue that can be listened to. #[derive(Debug, PartialEq)] @@ -59,7 +62,7 @@ pub trait SigningQueue: Send + Sync { /// Removes a request from the queue. /// Notifies possible token holders that transaction was confirmed and given hash was assigned. - fn request_confirmed(&self, id: U256, hash: H256) -> Option; + fn request_confirmed(&self, id: U256, result: RpcResult) -> Option; /// Returns a request if it is contained in the queue. fn peek(&self, id: &U256) -> Option; @@ -75,7 +78,7 @@ enum ConfirmationResult { /// The transaction has been rejected. Rejected, /// The transaction has been confirmed. - Confirmed(H256), + Confirmed(RpcResult), } /// Time you need to confirm the transaction in UI. @@ -100,7 +103,7 @@ pub struct ConfirmationPromise { impl ConfirmationToken { /// Submit solution to all listeners - fn resolve(&self, result: Option) { + fn resolve(&self, result: Option) { let mut res = self.result.lock().unwrap(); *res = result.map_or(ConfirmationResult::Rejected, |h| ConfirmationResult::Confirmed(h)); // Notify listener @@ -119,8 +122,8 @@ impl ConfirmationPromise { /// Blocks current thread and awaits for /// resolution of the transaction (rejected / confirmed) /// Returns `None` if transaction was rejected or timeout reached. - /// Returns `Some(hash)` if transaction was confirmed. - pub fn wait_with_timeout(&self) -> Option { + /// Returns `Some(result)` if transaction was confirmed. + pub fn wait_with_timeout(&self) -> Option { let timeout = Duration::from_secs(QUEUE_TIMEOUT_DURATION_SEC); let deadline = Instant::now() + timeout; @@ -137,7 +140,7 @@ impl ConfirmationPromise { // Check the result match *res { ConfirmationResult::Rejected => return None, - ConfirmationResult::Confirmed(h) => return Some(h), + ConfirmationResult::Confirmed(ref h) => return Some(h.clone()), ConfirmationResult::Waiting => continue, } } @@ -204,12 +207,12 @@ impl ConfirmationsQueue { /// Removes transaction from this queue and notifies `ConfirmationPromise` holders about the result. /// Notifies also a receiver about that event. - fn remove(&self, id: U256, result: Option) -> Option { + fn remove(&self, id: U256, result: Option) -> Option { let token = self.queue.write().unwrap().remove(&id); if let Some(token) = token { // notify receiver about the event - self.notify(result.map_or_else( + self.notify(result.clone().map_or_else( || QueueEvent::RequestRejected(id), |_| QueueEvent::RequestConfirmed(id) )); @@ -265,9 +268,9 @@ impl SigningQueue for ConfirmationsQueue { self.remove(id, None) } - fn request_confirmed(&self, id: U256, hash: H256) -> Option { + fn request_confirmed(&self, id: U256, result: RpcResult) -> Option { debug!(target: "own_tx", "Signer: Transaction confirmed ({:?}).", id); - self.remove(id, Some(hash)) + self.remove(id, Some(result)) } fn requests(&self) -> Vec { @@ -286,6 +289,7 @@ mod test { use util::numbers::{U256, H256}; use v1::types::TransactionRequest; use super::*; + use jsonrpc_core::to_value; fn request() -> TransactionRequest { TransactionRequest { @@ -317,10 +321,10 @@ mod test { // Just wait for the other thread to start thread::sleep(Duration::from_millis(100)); } - queue.request_confirmed(id, H256::from(1)); + queue.request_confirmed(id, to_value(&H256::from(1))); // then - assert_eq!(handle.join().expect("Thread should finish nicely"), H256::from(1)); + assert_eq!(handle.join().expect("Thread should finish nicely"), to_value(&H256::from(1))); } #[test] diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs index f8c3c343d..591eae059 100644 --- a/rpc/src/v1/impls/eth_signing.rs +++ b/rpc/src/v1/impls/eth_signing.rs @@ -25,7 +25,7 @@ use util::keys::store::AccountProvider; use v1::helpers::{SigningQueue, ConfirmationsQueue}; use v1::traits::EthSigning; use v1::types::TransactionRequest; -use v1::impls::sign_and_dispatch; +use v1::impls::{sign_and_dispatch, error_codes}; /// Implementation of functions that require signing when no trusted signer is used. @@ -45,6 +45,7 @@ impl EthSigningQueueClient { impl EthSigning for EthSigningQueueClient { fn sign(&self, _params: Params) -> Result { + warn!("Invoking eth_sign is not yet supported with signer enabled."); // TODO [ToDr] Implement sign when rest of the signing queue is ready. rpc_unimplemented!() } @@ -55,7 +56,7 @@ impl EthSigning for EthSigningQueueClient { let queue = take_weak!(self.queue); let id = queue.add_request(request); let result = id.wait_with_timeout(); - to_value(&result.unwrap_or_else(H256::new)) + result.unwrap_or_else(|| to_value(&H256::new())) }) } } @@ -93,7 +94,9 @@ impl EthSigning for EthSigningUnsafeClient 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())) + take_weak!(self.accounts).sign(&addr, &msg) + .map(|v| to_value(&v)) + .unwrap_or_else(|e| Err(account_locked(format!("Error: {:?}", e)))) }) } @@ -102,10 +105,17 @@ impl EthSigning for EthSigningUnsafeClient where .and_then(|(request, )| { let accounts = take_weak!(self.accounts); match accounts.account_secret(&request.from) { - Ok(secret) => to_value(&sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret)), - Err(_) => to_value(&H256::zero()) + Ok(secret) => sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret), + Err(e) => Err(account_locked(format!("Error: {:?}", e))), } }) } - +} + +fn account_locked(data: String) -> Error { + Error { + code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED), + message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(), + data: Some(Value::String(data)), + } } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 7fdf57249..03f4b34ed 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -54,14 +54,16 @@ pub use self::traces::TracesClient; pub use self::rpc::RpcClient; use v1::types::TransactionRequest; +use ethcore::error::Error as EthcoreError; use ethcore::miner::{AccountDetails, MinerService}; use ethcore::client::MiningBlockChainClient; use ethcore::transaction::{Action, SignedTransaction, Transaction}; use util::numbers::*; use util::rlp::encode; use util::bytes::ToPretty; +use jsonrpc_core::{Error, ErrorCode, Value, to_value}; -fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> H256 +fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result where C: MiningBlockChainClient, M: MinerService { let hash = signed_transaction.hash(); @@ -72,10 +74,12 @@ fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedT } }); - import.map(|_| hash).unwrap_or(H256::zero()) + import + .map_err(transaction_error) + .and_then(|_| to_value(&hash)) } -fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, secret: H256) -> H256 +fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, secret: H256) -> Result where C: MiningBlockChainClient, M: MinerService { let signed_transaction = { @@ -97,3 +101,48 @@ fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, s trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); dispatch_transaction(&*client, &*miner, signed_transaction) } + +mod error_codes { + // NOTE [ToDr] Codes from -32000 to -32099 + pub const UNKNOWN_ERROR: i64 = -32002; + pub const TRANSACTION_ERROR: i64 = -32010; + pub const ACCOUNT_LOCKED: i64 = -32020; +} + +fn transaction_error(error: EthcoreError) -> Error { + use ethcore::error::TransactionError::*; + + if let EthcoreError::Transaction(e) = error { + let msg = match e { + AlreadyImported => "Transaction with the same hash was already imported.".into(), + Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), + TooCheapToReplace => { + "Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into() + }, + LimitReached => { + "There is too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into() + }, + InsufficientGasPrice { minimal, got } => { + format!("Transaction fee is to low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got) + }, + InsufficientBalance { balance, cost } => { + format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance) + }, + GasLimitExceeded { limit, got } => { + format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) + }, + InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), + }; + Error { + code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR), + message: msg, + data: None, + } + } else { + Error { + code: ErrorCode::ServerError(error_codes::UNKNOWN_ERROR), + message: "Unknown error when sending transaction.".into(), + data: Some(Value::String(format!("{:?}", error))), + } + } +} diff --git a/rpc/src/v1/impls/personal_signer.rs b/rpc/src/v1/impls/personal_signer.rs index 88bf9a5d1..0c1fcb7f1 100644 --- a/rpc/src/v1/impls/personal_signer.rs +++ b/rpc/src/v1/impls/personal_signer.rs @@ -73,9 +73,9 @@ impl PersonalSigner for SignerClient { - let hash = sign_and_dispatch(&*client, &*miner, request, secret); - queue.request_confirmed(id, hash); - Some(to_value(&hash)) + let res = sign_and_dispatch(&*client, &*miner, request, secret); + queue.request_confirmed(id, res.clone()); + Some(res) }, Err(_) => None } From 818b87e3118179a7ebf3784235565266d8ed82c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 15 Jun 2016 09:01:57 +0200 Subject: [PATCH 02/17] Fixing returned value --- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/personal.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index b0d6abcf0..5c205c087 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -499,7 +499,7 @@ impl Eth for EthClient where .and_then(|(raw_transaction, )| { let raw_transaction = raw_transaction.to_vec(); match UntrustedRlp::new(&raw_transaction).as_val() { - Ok(signed_transaction) => to_value(&dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction)), + Ok(signed_transaction) => dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), signed_transaction), Err(_) => to_value(&H256::zero()), } }) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index c62c71453..4f9e307cb 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -92,7 +92,7 @@ impl Personal for PersonalClient .and_then(|(request, password)| { let accounts = take_weak!(self.accounts); match accounts.locked_account_secret(&request.from, &password) { - Ok(secret) => to_value(&sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret)), + Ok(secret) => sign_and_dispatch(&*take_weak!(self.client), &*take_weak!(self.miner), request, secret), Err(_) => to_value(&H256::zero()), } }) From 680337530129b22e6a531a49fbf7a7a69f7e58c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 15 Jun 2016 18:32:21 +0200 Subject: [PATCH 03/17] Consolidating all RPC error codes --- rpc/src/v1/impls/eth.rs | 10 +++------- rpc/src/v1/impls/mod.rs | 16 +++++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 28ba1a7de..de68452e8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -37,7 +37,7 @@ use ethcore::filter::Filter as EthcoreFilter; use self::ethash::SeedHashCompute; 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 v1::impls::{dispatch_transaction, error_codes}; use serde; /// Eth rpc implementation. @@ -210,13 +210,9 @@ fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNum } } -// must be in range [-32099, -32000] -const UNSUPPORTED_REQUEST_CODE: i64 = -32000; -const NO_WORK_CODE: i64 = -32001; - fn make_unsupported_err() -> Error { Error { - code: ErrorCode::ServerError(UNSUPPORTED_REQUEST_CODE), + code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE), message: "Unsupported request.".into(), data: None } @@ -224,7 +220,7 @@ fn make_unsupported_err() -> Error { fn no_work_err() -> Error { Error { - code: ErrorCode::ServerError(NO_WORK_CODE), + code: ErrorCode::ServerError(error_codes::NO_WORK_CODE), message: "Still syncing.".into(), data: None } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 03f4b34ed..8ea02b8b3 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -63,6 +63,15 @@ use util::rlp::encode; use util::bytes::ToPretty; use jsonrpc_core::{Error, ErrorCode, Value, to_value}; +mod error_codes { + // NOTE [ToDr] Codes from [-32099, -32000] + pub const UNSUPPORTED_REQUEST_CODE: i64 = -32000; + pub const NO_WORK_CODE: i64 = -32001; + pub const UNKNOWN_ERROR: i64 = -32002; + pub const TRANSACTION_ERROR: i64 = -32010; + pub const ACCOUNT_LOCKED: i64 = -32020; +} + fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result where C: MiningBlockChainClient, M: MinerService { let hash = signed_transaction.hash(); @@ -102,13 +111,6 @@ fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, s dispatch_transaction(&*client, &*miner, signed_transaction) } -mod error_codes { - // NOTE [ToDr] Codes from -32000 to -32099 - pub const UNKNOWN_ERROR: i64 = -32002; - pub const TRANSACTION_ERROR: i64 = -32010; - pub const ACCOUNT_LOCKED: i64 = -32020; -} - fn transaction_error(error: EthcoreError) -> Error { use ethcore::error::TransactionError::*; From 7284df9bf5936646f2b057474f0308b61423991e Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Wed, 15 Jun 2016 19:01:58 +0200 Subject: [PATCH 04/17] Fixed loosing peers on incoming connections. (#1293) * Deactivate peer if it has no new data * Fixed node table timer registration * Fixed handshake timeout expiration * Extra trace * Fixed session count calculation * Only deactivate incapable peers in ChainHead state * Timer registration is not needed --- sync/src/chain.rs | 8 +++++++- util/src/network/handshake.rs | 5 +++-- util/src/network/host.rs | 7 +++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 90e18d8e8..611035b3d 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -405,6 +405,7 @@ impl ChainSync { } if item_count == 0 && (self.state == SyncState::Blocks || self.state == SyncState::NewBlocks) { self.deactivate_peer(io, peer_id); //TODO: is this too harsh? + self.continue_sync(io); return Ok(()); } @@ -452,7 +453,12 @@ impl ChainSync { // Disable the peer for this syncing round if it gives invalid chain if !valid_response { - trace!(target: "sync", "{} Disabled for invalid headers response", peer_id); + trace!(target: "sync", "{} Deactivated for invalid headers response", peer_id); + self.deactivate_peer(io, peer_id); + } + if headers.is_empty() && self.state == SyncState::ChainHead { + // Peer does not have any new subchain heads, deactivate it nd try with another + trace!(target: "sync", "{} Deactivated for no data", peer_id); self.deactivate_peer(io, peer_id); } match self.state { diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 90e3bc67d..179309a6f 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -128,7 +128,6 @@ impl Handshake { /// Readable IO handler. Drives the state change. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { if !self.expired() { - io.clear_timer(self.connection.token).ok(); match self.state { HandshakeState::New => {} HandshakeState::ReadingAuth => { @@ -151,7 +150,9 @@ impl Handshake { try!(self.read_ack_eip8(host.secret(), &data)); }; }, - HandshakeState::StartSession => {}, + HandshakeState::StartSession => { + io.clear_timer(self.connection.token).ok(); + }, } } Ok(()) diff --git a/util/src/network/host.rs b/util/src/network/host.rs index b37538c9c..de6908200 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -523,11 +523,13 @@ impl Host where Message: Send + Sync + Clone { } let nodes = if pin { self.pinned_nodes.clone() } else { self.nodes.read().unwrap().nodes() }; + let mut started: usize = 0; for id in nodes.iter().filter(|ref id| !self.have_session(id) && !self.connecting_to(id)) .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { self.connect_peer(&id, io); + started += 1; } - debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); + debug!(target: "network", "Connecting peers: {} sessions, {} pending, {} started", self.session_count(), self.handshake_count(), started); } #[cfg_attr(feature="dev", allow(single_match))] @@ -650,6 +652,7 @@ impl Host where Message: Send + Sync + Clone { break; }, Ok(SessionData::Ready) => { + self.num_sessions.fetch_add(1, AtomicOrdering::SeqCst); if !s.info.originated { let session_count = self.session_count(); let ideal_peers = { self.info.read().unwrap().deref().config.ideal_peers }; @@ -667,7 +670,6 @@ impl Host where Message: Send + Sync + Clone { } } } - 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); @@ -828,6 +830,7 @@ impl IoHandler> for Host where Messa io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, NODE_TABLE => { + trace!(target: "network", "Refreshing node table"); self.nodes.write().unwrap().clear_useless(); }, _ => match self.timers.read().unwrap().get(&token).cloned() { From 5538527016b9e1362096dda93192b6b9adae4159 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 15 Jun 2016 20:52:00 +0300 Subject: [PATCH 05/17] x64 path --- nsis/installer.nsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 2c17a2543..f352e0b87 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -13,7 +13,7 @@ RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) -InstallDir "$PROGRAMFILES\${COMPANYNAME}\${APPNAME}" +InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" LicenseData "..\LICENSE" Name "${COMPANYNAME} ${APPNAME}" From 7649037e51af1fdc885a5f09cce0b2c36518acae Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 15 Jun 2016 21:40:41 +0300 Subject: [PATCH 06/17] firewall rules --- nsis/installer.nsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/nsis/installer.nsi b/nsis/installer.nsi index f352e0b87..10143306a 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -56,6 +56,18 @@ section "install" createDirectory "$SMPROGRAMS\${COMPANYNAME}" createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" "$INSTDIR\parity.exe" "ui" "$INSTDIR\logo.ico" + # Firewall remove rules if exists + SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" + SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" + SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" + SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" + + # Firewall exception rules + SimpleFC::AdvAddRule "Parity incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" 30303 "" "" "" + SimpleFC::AdvAddRule "Parity outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" + SimpleFC::AdvAddRule "Parity web queries (TCP:80)" "" 6 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 80 "" "" + SimpleFC::AdvAddRule "Parity UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\parity.exe" "" "" "Parity" "" 30303 "" "" + # Registry information for add/remove programs WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${COMPANYNAME} - ${APPNAME} - ${DESCRIPTION}" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" @@ -106,6 +118,12 @@ section "uninstall" # Try to remove the install directory - this will only happen if it is empty rmDir $INSTDIR + # Firewall exception rules + SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" + SimpleFC::AdvRemoveRule "Parity outgoing peers (TCP:30303)" + SimpleFC::AdvRemoveRule "Parity web queries (TCP:80)" + SimpleFC::AdvRemoveRule "Parity UDP discovery (UDP:30303)" + # Remove uninstaller information from the registry DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" From 9603597da79ebcac99d4e018c960ce6c511c9880 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jun 2016 21:31:19 +0200 Subject: [PATCH 07/17] Fix read-ahead bug. Re-ahead 8 bytes rather than 3 to ensure large blocks import fine. --- parity/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 1467eaa50..e1890ff0f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -398,7 +398,7 @@ fn execute_import(conf: Configuration) { Box::new(::std::io::stdin()) }; - let mut first_bytes: Bytes = vec![0; 3]; + let mut first_bytes: Bytes = vec![0; 8]; let mut first_read = 0; let format = match conf.args.flag_format { @@ -438,13 +438,13 @@ fn execute_import(conf: Configuration) { match format { DataFormat::Binary => { loop { - let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; 3]}; + let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; 8]}; let n = if first_read > 0 {first_read} else {instream.read(&mut(bytes[..])).unwrap_or_else(|_| die!("Error reading from the file/stream."))}; if n == 0 { break; } first_read = 0; let s = PayloadInfo::from(&(bytes[..])).unwrap_or_else(|e| die!("Invalid RLP in the file/stream: {:?}", e)).total(); bytes.resize(s, 0); - instream.read_exact(&mut(bytes[3..])).unwrap_or_else(|_| die!("Error reading from the file/stream.")); + instream.read_exact(&mut(bytes[8..])).unwrap_or_else(|_| die!("Error reading from the file/stream.")); do_import(bytes); } } From 80e56cb8d7c48bf6aa9236c1f48ba00c9896e82b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jun 2016 23:12:43 +0200 Subject: [PATCH 08/17] Refactor to use a const. --- parity/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index e1890ff0f..8b99f463b 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -398,7 +398,9 @@ fn execute_import(conf: Configuration) { Box::new(::std::io::stdin()) }; - let mut first_bytes: Bytes = vec![0; 8]; + const READAHEAD_BYTES: usize = 8; + + let mut first_bytes: Bytes = vec![0; READAHEAD_BYTES]; let mut first_read = 0; let format = match conf.args.flag_format { @@ -438,13 +440,13 @@ fn execute_import(conf: Configuration) { match format { DataFormat::Binary => { loop { - let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; 8]}; + let mut bytes: Bytes = if first_read > 0 {first_bytes.clone()} else {vec![0; READAHEAD_BYTES]}; let n = if first_read > 0 {first_read} else {instream.read(&mut(bytes[..])).unwrap_or_else(|_| die!("Error reading from the file/stream."))}; if n == 0 { break; } first_read = 0; let s = PayloadInfo::from(&(bytes[..])).unwrap_or_else(|e| die!("Invalid RLP in the file/stream: {:?}", e)).total(); bytes.resize(s, 0); - instream.read_exact(&mut(bytes[8..])).unwrap_or_else(|_| die!("Error reading from the file/stream.")); + instream.read_exact(&mut(bytes[READAHEAD_BYTES..])).unwrap_or_else(|_| die!("Error reading from the file/stream.")); do_import(bytes); } } From 1e9da1e0fade195101eac0220590324bbc3d25ea Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 16 Jun 2016 11:21:35 +0200 Subject: [PATCH 09/17] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index acd873b74..e942943ec 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do - Windows Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from - https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe and use the following command to install and set up the msvc toolchain: + https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain: ``` $ rustup default stable-x86_64-pc-windows-msvc ``` @@ -73,4 +73,4 @@ To get started, just run $ ./target/release/parity ``` -and parity will begin syncing the Ethereum blockchain. \ No newline at end of file +and parity will begin syncing the Ethereum blockchain. From 88b03580ff855749114ecbc42302016f5fc0763d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jun 2016 12:44:08 +0200 Subject: [PATCH 10/17] Gas price statistics. (#1291) * Gas price statistics. Affects eth_gasPrice. Added ethcore_gasPriceStatistics. Closes #1265 * Fix a bug in eth_gasPrice * Fix tests. * Revert minor alteration. * Tests for gas_price_statistics. - Tests; - Additional infrastructure for generating test blocks with transactions. --- ethcore/res/null.json | 33 +++++++++++ ethcore/src/client/client.rs | 3 +- ethcore/src/client/mod.rs | 28 +++++++++ ethcore/src/spec/spec.rs | 5 ++ ethcore/src/tests/client.rs | 12 ++++ ethcore/src/tests/helpers.rs | 75 +++++++++++++++++++----- ethcore/src/verification/verification.rs | 2 +- parity/rpc_apis.rs | 2 +- rpc/src/v1/impls/eth.rs | 14 ++++- rpc/src/v1/impls/ethcore.rs | 37 +++++++++--- rpc/src/v1/tests/mocked/ethcore.rs | 62 +++++++++++++------- rpc/src/v1/traits/ethcore.rs | 4 ++ 12 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 ethcore/res/null.json diff --git a/ethcore/res/null.json b/ethcore/res/null.json new file mode 100644 index 000000000..b9b2b1260 --- /dev/null +++ b/ethcore/res/null.json @@ -0,0 +1,33 @@ +{ + "name": "Morden", + "engine": { + "Null": null + }, + "params": { + "accountStartNonce": "0x0", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x2" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x00006d6f7264656e", + "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2fefd8" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "0", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "0", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "0", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "0", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "9cce34f7ab185c7aba1b7c8140d620b4bda941d6": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "0" } + } +} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 75a60204f..85a3d693d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -770,8 +770,7 @@ impl MiningBlockChainClient for Client where V: Verifier { author, gas_floor_target, extra_data, - ).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \ - Therefore creating an OpenBlock with the best block's header will not fail."); + ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles self.chain diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index dbd09ea4a..3fec68815 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -34,6 +34,7 @@ pub use env_info::{LastHashes, EnvInfo}; use util::bytes::Bytes; use util::hash::{Address, H256, H2048}; use util::numbers::U256; +use util::Itertools; use blockchain::TreeRoute; use block_queue::BlockQueueInfo; use block::OpenBlock; @@ -41,6 +42,7 @@ use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; +use views::BlockView; use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use trace::LocalizedTrace; @@ -193,6 +195,32 @@ pub trait BlockChainClient : Sync + Send { /// list all transactions fn all_transactions(&self) -> Vec; + + /// Get the gas price distribution. + fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result, ()> { + let mut h = self.chain_info().best_block_hash; + let mut corpus = Vec::new(); + for _ in 0..sample_size { + let block_bytes = self.block(BlockID::Hash(h)).expect("h is either the best_block_hash or an ancestor; qed"); + let block = BlockView::new(&block_bytes); + let header = block.header_view(); + if header.number() == 0 { + break; + } + block.transaction_views().iter().foreach(|t| corpus.push(t.gas_price())); + h = header.parent_hash().clone(); + } + corpus.sort(); + let n = corpus.len(); + if n > 0 { + Ok((0..(distribution_size + 1)) + .map(|i| corpus[i * (n - 1) / distribution_size]) + .collect::>() + ) + } else { + Err(()) + } + } } /// Extended client interface used for mining diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 743f1bd9b..02b311b24 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -244,6 +244,11 @@ impl Spec { pub fn new_test() -> Spec { Spec::load(include_bytes!("../../res/null_morden.json")) } + + /// Create a new Spec which is a NullEngine consensus with a premine of address whose secret is sha3(''). + pub fn new_null() -> Spec { + Spec::load(include_bytes!("../../res/null.json")) + } } #[cfg(test)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d87b41b62..a5459035e 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -112,6 +112,18 @@ fn can_collect_garbage() { assert!(client.blockchain_cache_info().blocks < 100 * 1024); } +#[test] +fn can_generate_gas_price_statistics() { + let client_result = generate_dummy_client_with_data(16, 1, &vec_into![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let client = client_result.reference(); + let s = client.gas_price_statistics(8, 8).unwrap(); + assert_eq!(s, vec_into![8, 8, 9, 10, 11, 12, 13, 14, 15]); + let s = client.gas_price_statistics(16, 8).unwrap(); + assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]); + let s = client.gas_price_statistics(32, 8).unwrap(); + assert_eq!(s, vec_into![0, 1, 3, 5, 7, 9, 11, 13, 15]); +} + #[test] fn can_handle_long_fork() { let client_result = generate_dummy_client(1200); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 3b27ef4a4..151d53bba 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -17,6 +17,7 @@ use client::{BlockChainClient, Client, ClientConfig}; use common::*; use spec::*; +use block::{OpenBlock}; use blockchain::{BlockChain, Config as BlockChainConfig}; use state::*; use evm::Schedule; @@ -85,6 +86,7 @@ impl Engine for TestEngine { } } +// TODO: move everything over to get_null_spec. pub fn get_test_spec() -> Spec { Spec::new_test() } @@ -126,7 +128,7 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes { create_test_block(&create_unverifiable_block_header(order, parent_hash)) } -pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTransaction], uncles: &[Header]) -> Bytes { +pub fn create_test_block_with_data(header: &Header, transactions: &[SignedTransaction], uncles: &[Header]) -> Bytes { let mut rlp = RlpStream::new_list(3); rlp.append(header); rlp.begin_list(transactions.len()); @@ -138,33 +140,74 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans } pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { + generate_dummy_client_with_spec_and_data(Spec::new_test, block_number, 0, &(vec![])) +} + +pub fn generate_dummy_client_with_data(block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> { + generate_dummy_client_with_spec_and_data(Spec::new_null, block_number, txs_per_block, tx_gas_prices) +} + +pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_number: u32, txs_per_block: usize, tx_gas_prices: &[U256]) -> GuardedTempResult> where F: Fn()->Spec { let dir = RandomTempPath::new(); - 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 client = Client::new(ClientConfig::default(), get_test_spec(), dir.as_path(), Arc::new(Miner::default()), IoChannel::disconnected()).unwrap(); let test_engine = &test_spec.engine; - let state_root = test_spec.genesis_header().state_root; - let mut rolling_hash = test_spec.genesis_header().hash(); - let mut rolling_block_number = 1; + + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + test_spec.ensure_db_good(db.as_hashdb_mut()); + let vm_factory = Default::default(); + let genesis_header = test_spec.genesis_header(); + let mut rolling_timestamp = 40; + let mut last_hashes = vec![]; + let mut last_header = genesis_header.clone(); + let kp = KeyPair::from_secret("".sha3()).unwrap() ; + let author = kp.address(); + + let mut n = 0; for _ in 0..block_number { - let mut header = Header::new(); + last_hashes.push(last_header.hash()); - header.gas_limit = test_engine.params().min_gas_limit; - header.difficulty = U256::from(0x20000); - header.timestamp = rolling_timestamp; - header.number = rolling_block_number; - header.parent_hash = rolling_hash; - header.state_root = state_root.clone(); + // forge block. + let mut b = OpenBlock::new( + test_engine.deref(), + &vm_factory, + false, + db, + &last_header, + last_hashes.clone(), + author.clone(), + 3141562.into(), + vec![] + ).unwrap(); + b.set_difficulty(U256::from(0x20000)); + rolling_timestamp += 10; + b.set_timestamp(rolling_timestamp); - rolling_hash = header.hash(); - rolling_block_number = rolling_block_number + 1; - rolling_timestamp = rolling_timestamp + 10; + // first block we don't have any balance, so can't send any transactions. + for _ in 0..txs_per_block { + b.push_transaction(Transaction { + nonce: n.into(), + gas_price: tx_gas_prices[n % tx_gas_prices.len()], + gas: 100000.into(), + action: Action::Create, + data: vec![], + value: U256::zero(), + }.sign(kp.secret()), None).unwrap(); + n += 1; + } - if let Err(e) = client.import_block(create_test_block(&header)) { + let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap(); + + if let Err(e) = client.import_block(b.rlp_bytes()) { panic!("error importing block which is valid by definition: {:?}", e); } + + last_header = BlockView::new(&b.rlp_bytes()).header(); + db = b.drain(); } client.flush_queue(); client.import_verified_blocks(&IoChannel::disconnected()); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 6511a8ddd..c6b75416b 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -361,7 +361,7 @@ mod tests { nonce: U256::from(2) }.sign(&keypair.secret()); - let good_transactions = [ &tr1, &tr2 ]; + let good_transactions = [ tr1.clone(), tr2.clone() ]; let diff_inc = U256::from(0x40); diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index d9085fc31..f4b2d067f 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -159,7 +159,7 @@ pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet 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()) + server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) }, Api::EthcoreSet => { server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate()) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2d337e73c..80245708f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -153,15 +153,23 @@ impl EthClient where } } + fn default_gas_price(&self) -> Result { + let miner = take_weak!(self.miner); + Ok(take_weak!(self.client) + .gas_price_statistics(100, 8) + .map(|x| x[4]) + .unwrap_or_else(|_| miner.sensible_gas_price()) + ) + } + 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()), + gas_price: request.gas_price.unwrap_or_else(|| self.default_gas_price().expect("call only fails if client or miner are unavailable; client and miner are both available to be here; qed")), value: request.value.unwrap_or_else(U256::zero), data: request.data.map_or_else(Vec::new, |d| d.to_vec()) }.fake_sign(from)) @@ -293,7 +301,7 @@ impl Eth for EthClient where fn gas_price(&self, params: Params) -> Result { match params { - Params::None => to_value(&take_weak!(self.miner).sensible_gas_price()), + Params::None => to_value(&try!(self.default_gas_price())), _ => Err(Error::invalid_params()) } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index b3fe894c6..e77f46f5d 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -15,30 +15,34 @@ // along with Parity. If not, see . //! Ethcore-specific rpc implementation. -use util::RotatingLogger; +use util::{RotatingLogger}; use util::network_settings::NetworkSettings; use util::misc::version_data; use std::sync::{Arc, Weak}; use std::ops::Deref; -use std::collections::BTreeMap; +use std::collections::{BTreeMap}; +use ethcore::client::{MiningBlockChainClient}; use jsonrpc_core::*; use ethcore::miner::MinerService; use v1::traits::Ethcore; use v1::types::{Bytes}; /// Ethcore implementation. -pub struct EthcoreClient where +pub struct EthcoreClient where + C: MiningBlockChainClient, M: MinerService { + client: Weak, miner: Weak, logger: Arc, settings: Arc, } -impl EthcoreClient where M: MinerService { +impl EthcoreClient where C: MiningBlockChainClient, 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, @@ -46,7 +50,7 @@ impl EthcoreClient where M: MinerService { } } -impl Ethcore for EthcoreClient where M: MinerService + 'static { +impl Ethcore for EthcoreClient where M: MinerService + 'static, C: MiningBlockChainClient + 'static { fn transactions_limit(&self, _: Params) -> Result { to_value(&take_weak!(self.miner).transactions_limit()) @@ -97,8 +101,23 @@ impl Ethcore for EthcoreClient where M: MinerService + 'static { Ok(Value::Object(map)) } - fn default_extra_data(&self, _params: Params) -> Result { - let version = version_data(); - to_value(&Bytes::new(version)) + fn default_extra_data(&self, params: Params) -> Result { + match params { + Params::None => to_value(&Bytes::new(version_data())), + _ => Err(Error::invalid_params()), + } + } + + fn gas_price_statistics(&self, params: Params) -> Result { + match params { + Params::None => match take_weak!(self.client).gas_price_statistics(100, 8) { + Ok(stats) => to_value(&stats + .iter() + .map(|x| to_value(&x).expect("x must be U256; qed")) + .collect::>()), + _ => Err(Error::internal_error()), + }, + _ => Err(Error::invalid_params()), + } } } diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index 90103adef..68c33ecce 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -20,6 +20,7 @@ use jsonrpc_core::IoHandler; use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient}; use ethcore::miner::MinerService; use v1::tests::helpers::TestMinerService; +use ethcore::client::{TestBlockChainClient}; use util::numbers::*; use rustc_serialize::hex::FromHex; use util::log::RotatingLogger; @@ -29,6 +30,10 @@ fn miner_service() -> Arc { Arc::new(TestMinerService::default()) } +fn client_service() -> Arc { + Arc::new(TestBlockChainClient::default()) +} + fn logger() -> Arc { Arc::new(RotatingLogger::new("rpc=trace".to_owned())) } @@ -45,19 +50,20 @@ 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()) } fn ethcore_set_client(miner: &Arc) -> EthcoreSetClient { - EthcoreSetClient::new(&miner) + EthcoreSetClient::new(miner) } #[test] fn rpc_ethcore_extra_data() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#; @@ -72,8 +78,9 @@ fn rpc_ethcore_default_extra_data() { use util::ToPretty; let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#; @@ -85,8 +92,9 @@ fn rpc_ethcore_default_extra_data() { #[test] fn rpc_ethcore_gas_floor_target() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#; @@ -98,8 +106,9 @@ fn rpc_ethcore_gas_floor_target() { #[test] fn rpc_ethcore_min_gas_price() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#; @@ -111,8 +120,9 @@ fn rpc_ethcore_min_gas_price() { #[test] fn rpc_ethcore_set_min_gas_price() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; @@ -125,8 +135,9 @@ fn rpc_ethcore_set_min_gas_price() { #[test] fn rpc_ethcore_set_gas_floor_target() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; @@ -139,8 +150,9 @@ fn rpc_ethcore_set_gas_floor_target() { #[test] fn rpc_ethcore_set_extra_data() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; @@ -153,8 +165,9 @@ fn rpc_ethcore_set_extra_data() { #[test] fn rpc_ethcore_set_author() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; @@ -167,10 +180,11 @@ fn rpc_ethcore_set_author() { #[test] fn rpc_ethcore_dev_logs() { let miner = miner_service(); + let client = client_service(); 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); io.add_delegate(ethcore_set_client(&miner).to_delegate()); @@ -184,8 +198,9 @@ fn rpc_ethcore_dev_logs() { #[test] fn rpc_ethcore_dev_logs_levels() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#; @@ -196,8 +211,9 @@ fn rpc_ethcore_dev_logs_levels() { #[test] fn rpc_ethcore_set_transactions_limit() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#; @@ -210,8 +226,9 @@ fn rpc_ethcore_set_transactions_limit() { #[test] fn rpc_ethcore_transactions_limit() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#; @@ -223,8 +240,9 @@ fn rpc_ethcore_transactions_limit() { #[test] fn rpc_ethcore_net_chain() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#; @@ -236,8 +254,9 @@ fn rpc_ethcore_net_chain() { #[test] fn rpc_ethcore_net_max_peers() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#; @@ -249,8 +268,9 @@ fn rpc_ethcore_net_max_peers() { #[test] fn rpc_ethcore_net_port() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#; @@ -262,8 +282,9 @@ fn rpc_ethcore_net_port() { #[test] fn rpc_ethcore_rpc_settings() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#; @@ -275,8 +296,9 @@ fn rpc_ethcore_rpc_settings() { #[test] fn rpc_ethcore_node_name() { let miner = miner_service(); + let client = client_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner).to_delegate()); io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#; diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 4ce3eca59..1dd00ff73 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -57,6 +57,9 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns default extra data fn default_extra_data(&self, _: Params) -> Result; + /// Returns distribution of gas price in latest blocks. + fn gas_price_statistics(&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)); @@ -73,6 +76,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static { delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings); delegate.add_method("ethcore_nodeName", Ethcore::node_name); delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data); + delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics); delegate } From 07641b8f0ac9e296973a3e22fec0052a623c7084 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 16 Jun 2016 16:14:22 +0400 Subject: [PATCH 11/17] Key load avoid warning (#1303) * avoid warning with key * fix intendations * more intendation fix * ok() instead of expect() --- util/src/keys/directory.rs | 11 +++++++---- util/src/keys/store.rs | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 32ac14b55..385a400c7 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -428,9 +428,9 @@ impl KeyFileContent { let crypto = match as_object.get("crypto") { None => { return Err(KeyFileParseError::NoCryptoSection); } Some(crypto_json) => match KeyFileCrypto::from_json(crypto_json) { - Ok(crypto) => crypto, - Err(crypto_error) => { return Err(KeyFileParseError::Crypto(crypto_error)); } - } + Ok(crypto) => crypto, + Err(crypto_error) => { return Err(KeyFileParseError::Crypto(crypto_error)); } + } }; Ok(KeyFileContent { @@ -627,7 +627,10 @@ impl KeyDirectory { } } - + /// Checks if key exists + pub fn exists(&self, id: &Uuid) -> bool { + KeyDirectory::load_key(&self.key_path(id)).is_ok() + } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index f6f41745f..b8a1de272 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -294,9 +294,9 @@ impl SecretStore { if let Some(unlock) = read_lock.get(account) { (unlock.relock_on_use, match crypto::KeyPair::from_secret(unlock.secret) { Ok(pair) => match pair.sign(message) { - Ok(signature) => Ok(signature), - Err(_) => Err(SigningError::InvalidSecret) - }, + Ok(signature) => Ok(signature), + Err(_) => Err(SigningError::InvalidSecret) + }, Err(_) => Err(SigningError::InvalidSecret) }) } else { @@ -348,6 +348,10 @@ impl SecretStore { garbage_lock.shrink_to_fit(); } + + fn exists(&self, key: &H128) -> bool { + self.directory.exists(key) + } } fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) { @@ -408,7 +412,7 @@ impl EncryptedHashMap for SecretStore { } fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { - let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; + let previous = if !self.exists(&key) { None } else { self.get(&key, password).ok() }; // crypto random initiators let salt = H256::random(); From 2a101baf1d4158487ad08a3ed773bdbf335a3d55 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 16 Jun 2016 19:02:55 +0400 Subject: [PATCH 12/17] Appveyor config for windows build+installer (#1302) * appveyor * proper dist name * quote * win-build config * proper build section * tests in release * plugin dir * cache binaries * quotes * escaped quotes * forces user dir * fixes * syntax * proper cahce dir * quotes? * root nsis instead of bin * submodules init * artifact path fix * no submodule * raw link here * another way to force cargo cache * include vc++ 2015 redist * fix name of the dist * ETHCORE -> Ethcore --- appveyor.yml | 29 +++++++++++++++++++++++++++++ nsis/installer.nsi | 7 ++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..b980aba42 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,29 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc +install: + - git submodule update --init --recursive + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-1.9.0-x86_64-pc-windows-msvc.exe" + - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -FileName nsis\SimpleFC.dll + - ps: Start-FileDownload "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -FileName nsis\vc_redist.x64.exe + - rust-1.9.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin;C:\Program Files (x86)\NSIS + - rustc -V + - cargo -V + +build: off + +test_script: + - cargo test --verbose --release + +after_test: + - cargo build --verbose --release + - makensis.exe nsis\installer.nsi + +artifacts: + - path: nsis\installer.exe + name: Windows Installer (x86_64) + +cache: + - target + - C:\users\appveyor\.cargo -> appveyor.yml diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 10143306a..fffcc1dd9 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -1,11 +1,13 @@ !define APPNAME "Parity" -!define COMPANYNAME "ETHCORE" +!define COMPANYNAME "Ethcore" !define DESCRIPTION "Fast, light, robust Ethereum implementation" !define VERSIONMAJOR 1 !define VERSIONMINOR 2 !define VERSIONBUILD 0 +!addplugindir .\ + !define HELPURL "https://github.com/ethcore/parity/wiki" # "Support Information" link !define UPDATEURL "https://github.com/ethcore/parity/releases" # "Product Updates" link !define ABOUTURL "https://github.com/ethcore/parity" # "Publisher" link @@ -47,6 +49,9 @@ section "install" # Files added here should be removed by the uninstaller (see section "uninstall") file /oname=parity.exe ..\target\release\parity.exe file "logo.ico" + file vc_redist.x64.exe + + ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart' # Add any other files for the install directory (license files, app data, etc) here # Uninstaller - See function un.onInit and section "uninstall" for configuration From 16412eb0c96eb0abd4b4d73d2f68958f2fbefb1d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 17 Jun 2016 22:15:18 +0200 Subject: [PATCH 13/17] DAO Rescue soft fork (#1309) * DAO Rescue soft fork * Address minor issues. * Fix tests. --- ethcore/src/error.rs | 3 +++ ethcore/src/ethereum/ethash.rs | 5 ++++- ethcore/src/evm/schedule.rs | 3 +++ ethcore/src/state.rs | 18 ++++++++++++++++++ rpc/src/v1/impls/mod.rs | 1 + 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 98aec917a..9be800e13 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -58,6 +58,8 @@ pub enum TransactionError { }, /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), + /// Transaction is invalid for some other reason. + DAORescue, } impl fmt::Display for TransactionError { @@ -76,6 +78,7 @@ impl fmt::Display for TransactionError { GasLimitExceeded { limit, got } => format!("Gas limit exceeded. Limit={}, Given={}", limit, got), InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), + DAORescue => "Transaction is invalid due to the DAO rescue.".into(), }; f.write_fmt(format_args!("Transaction error ({})", msg)) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index c8b8d7b31..d89499872 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -101,7 +101,10 @@ impl Engine for Ethash { if env_info.number < self.ethash_params.frontier_compatibility_mode_limit { Schedule::new_frontier() } else { - Schedule::new_homestead() + let mut s = Schedule::new_homestead(); + // TODO: make dependent on gaslimit > 4000000 of block 1760000. + s.block_dao_transactions = env_info.number >= 1760000; + s } } diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index f82157239..59f30e7d3 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -80,6 +80,8 @@ pub struct Schedule { pub tx_data_non_zero_gas: usize, /// Gas price for copying memory pub copy_gas: usize, + /// DAO Rescue softfork block + pub block_dao_transactions: bool, } impl Schedule { @@ -126,6 +128,7 @@ impl Schedule { tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, copy_gas: 3, + block_dao_transactions: false, } } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 204cea618..dc9ca582c 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -222,6 +222,24 @@ impl State { 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)); + let broken_dao = H256::from("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba"); + + // dao attack soft fork + if engine.schedule(&env_info).block_dao_transactions { + // collect all the addresses which have changed. + let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::>(); + + for a in addresses.iter() { + if self.code(a).map(|c| c.sha3() == broken_dao).unwrap_or(false) { + // Figure out if the balance has been reduced. + let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp); + if maybe_original.map(|original| *original.balance() > self.balance(a)).unwrap_or(false) { + return Err(Error::Transaction(TransactionError::DAORescue)); + } + } + } + } + // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod())); self.commit(); diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 8ea02b8b3..f69fa25ce 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -134,6 +134,7 @@ fn transaction_error(error: EthcoreError) -> Error { format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) }, InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), + DAORescue => "Transaction removes funds from a DAO.".into(), }; Error { code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR), From c9f8eff92df1291ac6cdce8788e6e9025e813c54 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Jun 2016 14:59:52 +0200 Subject: [PATCH 14/17] Change CLI default for gas floor target. --- parity/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/cli.rs b/parity/cli.rs index ba3cfc21a..0ec2bb094 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -120,7 +120,7 @@ Sealing/Mining Options: web service in turn and fallback on the last known good value [default: auto]. --gas-floor-target GAS Amount of gas per block to target when sealing a new - block [default: 4712388]. + block [default: 3141592]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. From 22e390f92294465661d01c56769ebeb4a4e8a235 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Jun 2016 15:00:12 +0200 Subject: [PATCH 15/17] Rename block_dao -> reject_dao. --- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/evm/schedule.rs | 4 ++-- ethcore/src/state.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index d89499872..a4291796a 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -103,7 +103,7 @@ impl Engine for Ethash { } else { let mut s = Schedule::new_homestead(); // TODO: make dependent on gaslimit > 4000000 of block 1760000. - s.block_dao_transactions = env_info.number >= 1760000; + s.reject_dao_transactions = env_info.number >= 1760000; s } } diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index 59f30e7d3..188e72373 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -81,7 +81,7 @@ pub struct Schedule { /// Gas price for copying memory pub copy_gas: usize, /// DAO Rescue softfork block - pub block_dao_transactions: bool, + pub reject_dao_transactions: bool, } impl Schedule { @@ -128,7 +128,7 @@ impl Schedule { tx_data_zero_gas: 4, tx_data_non_zero_gas: 68, copy_gas: 3, - block_dao_transactions: false, + reject_dao_transactions: false, } } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index dc9ca582c..7d045b455 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -225,7 +225,7 @@ impl State { let broken_dao = H256::from("7278d050619a624f84f51987149ddb439cdaadfba5966f7cfaea7ad44340a4ba"); // dao attack soft fork - if engine.schedule(&env_info).block_dao_transactions { + if engine.schedule(&env_info).reject_dao_transactions { // collect all the addresses which have changed. let addresses = self.cache.borrow().iter().map(|(addr, _)| addr.clone()).collect::>(); From 7208f9f95c2f72ec2b8160d346333f82a9d49a84 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Jun 2016 15:12:13 +0200 Subject: [PATCH 16/17] Unsaved file. Duh. --- sync/src/chain.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 021d8542a..3df478f9f 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -458,21 +458,12 @@ impl ChainSync { // Disable the peer for this syncing round if it gives invalid chain if !valid_response { trace!(target: "sync", "{} Deactivated for invalid headers response", peer_id); -<<<<<<< HEAD self.deactivate_peer(io, peer_id); } if headers.is_empty() && self.state == SyncState::ChainHead { // Peer does not have any new subchain heads, deactivate it nd try with another trace!(target: "sync", "{} Deactivated for no data", peer_id); self.deactivate_peer(io, peer_id); -======= - self.deactivate_peer(io, peer_id); - } - if headers.is_empty() { - // Peer does not have any new subchain heads, deactivate it nd try with another - trace!(target: "sync", "{} Deactivated for no data", peer_id); - self.deactivate_peer(io, peer_id); ->>>>>>> master } match self.state { SyncState::ChainHead => { From 47cd9ff34cdae38abb41b21cbf659a70f4c1cd20 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 18 Jun 2016 15:18:36 +0200 Subject: [PATCH 17/17] Remove code no longer in master :-S --- sync/src/chain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 3df478f9f..25f1eb6a3 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -460,7 +460,7 @@ impl ChainSync { trace!(target: "sync", "{} Deactivated for invalid headers response", peer_id); self.deactivate_peer(io, peer_id); } - if headers.is_empty() && self.state == SyncState::ChainHead { + if headers.is_empty() { // Peer does not have any new subchain heads, deactivate it nd try with another trace!(target: "sync", "{} Deactivated for no data", peer_id); self.deactivate_peer(io, peer_id);