diff --git a/Cargo.lock b/Cargo.lock index ff5317324..74e15eded 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,6 +545,7 @@ dependencies = [ "ethkey 0.3.0", "ethstore 0.2.0", "evm 0.1.0", + "fake-hardware-wallet 0.0.1", "fetch 0.1.0", "hardware-wallet 1.12.0", "hashdb 0.1.1", @@ -1072,6 +1073,14 @@ dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fake-hardware-wallet" +version = "0.0.1" +dependencies = [ + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethkey 0.3.0", +] + [[package]] name = "fdlimit" version = "0.1.1" @@ -2238,6 +2247,7 @@ dependencies = [ "ethkey 0.3.0", "ethstore 0.2.0", "fake-fetch 0.0.1", + "fake-hardware-wallet 0.0.1", "fetch 0.1.0", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index c15c3fd08..00406fa59 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -36,7 +36,6 @@ ethjson = { path = "../json" } ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } evm = { path = "evm" } -hardware-wallet = { path = "../hw" } heapsize = "0.4" itertools = "0.5" lazy_static = "1.0" @@ -70,6 +69,12 @@ journaldb = { path = "../util/journaldb" } tempdir = { version = "0.3", optional = true } kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } +[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies] +hardware-wallet = { path = "../hw" } + +[target.'cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))'.dependencies] +fake-hardware-wallet = { path = "../util/fake-hardware-wallet" } + [dev-dependencies] trie-standardmap = { path = "../util/trie-standardmap" } diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index a12aec867..e4289c60a 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -20,21 +20,23 @@ mod stores; use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; -use std::fmt; use std::collections::{HashMap, HashSet}; +use std::fmt; use std::time::{Instant, Duration}; -use parking_lot::RwLock; + +use ethstore::accounts_dir::MemoryDirectory; +use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; +use ethjson::misc::AccountMeta; use ethstore::{ SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, }; -use ethstore::accounts_dir::MemoryDirectory; -use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; -use ethjson::misc::AccountMeta; -use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; -use super::transaction::{Action, Transaction}; +use parking_lot::RwLock; + pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; +pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; +pub use super::transaction::{Action, Transaction}; /// Type of unlock. #[derive(Clone, PartialEq)] @@ -165,6 +167,7 @@ impl AccountProvider { /// Creates new account provider. pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; + if settings.enable_hardware_wallets { match HardwareWalletManager::new() { Ok(manager) => { @@ -289,8 +292,12 @@ impl AccountProvider { /// Returns addresses of hardware accounts. pub fn hardware_accounts(&self) -> Result, Error> { - let accounts = self.hardware_store.as_ref().map_or(Vec::new(), |h| h.list_wallets()); - Ok(accounts.into_iter().map(|a| a.address).collect()) + if let Some(accounts) = self.hardware_store.as_ref().map(|h| h.list_wallets()) { + if !accounts.is_empty() { + return Ok(accounts.into_iter().map(|a| a.address).collect()); + } + } + Err(SSError::Custom("No hardware wallet accounts were found".into())) } /// Get a list of paths to locked hardware wallets @@ -301,7 +308,7 @@ impl AccountProvider { Some(Ok(s)) => Ok(s), } } - + /// Provide a pin to a locked hardware wallet on USB path to unlock it pub fn hardware_pin_matrix_ack(&self, path: &str, pin: &str) -> Result { match self.hardware_store.as_ref().map(|h| h.pin_matrix_ack(path, pin)) { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 8d8b22c6a..f52afdcad 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -75,7 +75,7 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethjson; extern crate ethkey; -extern crate hardware_wallet; + extern crate hashdb; extern crate itertools; extern crate kvdb; @@ -99,7 +99,6 @@ extern crate ansi_term; extern crate unexpected; extern crate util_error; extern crate snappy; - extern crate ethabi; extern crate rustc_hex; extern crate stats; @@ -112,6 +111,12 @@ extern crate journaldb; #[cfg(any(test, feature = "json-tests", feature = "test-helpers"))] extern crate tempdir; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +extern crate hardware_wallet; + +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +extern crate fake_hardware_wallet as hardware_wallet; + #[macro_use] extern crate ethabi_derive; #[macro_use] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index d227f45f5..8487844bd 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -64,6 +64,12 @@ rlp = { path = "../util/rlp" } stats = { path = "../util/stats" } vm = { path = "../ethcore/vm" } +[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies] +hardware-wallet = { path = "../hw" } + +[target.'cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))'.dependencies] +fake-hardware-wallet = { path = "../util/fake-hardware-wallet" } + [dev-dependencies] ethcore = { path = "../ethcore", features = ["test-helpers"] } ethcore-network = { path = "../util/network" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 2d49a8c77..6356dc284 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -58,17 +58,21 @@ extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethkey; extern crate ethstore; -extern crate vm; extern crate fetch; +extern crate keccak_hash as hash; extern crate node_health; extern crate parity_reactor; extern crate parity_updater as updater; extern crate parity_version as version; +extern crate patricia_trie as trie; extern crate rlp; extern crate stats; -extern crate keccak_hash as hash; +extern crate vm; + +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; -extern crate patricia_trie as trie; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +extern crate fake_hardware_wallet as hardware_wallet; #[macro_use] extern crate log; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index b0e69edfb..c6f10400a 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -24,7 +24,6 @@ use light::cache::Cache as LightDataCache; use light::client::LightChainClient; use light::on_demand::{request, OnDemand}; use light::TransactionQueue as LightTransactionQueue; -use rlp; use hash::keccak; use ethereum_types::{H256, H520, Address, U256}; use bytes::Bytes; @@ -52,6 +51,7 @@ use v1::types::{ SignRequest as RpcSignRequest, DecryptRequest as RpcDecryptRequest, }; +use rlp; pub use self::nonce::Reservations; @@ -323,7 +323,7 @@ impl LightDispatcher { x.map(move |acc| acc.map_or(account_start_nonce, |acc| acc.nonce)) .map_err(|_| errors::no_light_peers()) ), - None => Box::new(future::err(errors::network_disabled())) + None => Box::new(future::err(errors::network_disabled())) } } } @@ -699,7 +699,6 @@ pub fn execute( if accounts.is_hardware_address(&address) { return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None))); } - let res = decrypt(&accounts, address, data, pass) .map(|result| result .map(RpcBytes) @@ -737,8 +736,8 @@ fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transacti SignedTransaction::new(t.with_signature(signature, chain_id)) .map_err(|e| { - debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e); - errors::account("Invalid signature generated", e) + debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e); + errors::account("Invalid signature generated", e) }) } diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 6e93132b9..9ef316b70 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -305,8 +305,8 @@ impl Parity for ParityClient { fn pending_transactions_stats(&self) -> Result> { let stats = self.light_dispatch.sync.transactions_stats(); Ok(stats.into_iter() - .map(|(hash, stats)| (hash.into(), stats.into())) - .collect() + .map(|(hash, stats)| (hash.into(), stats.into())) + .collect() ) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index d7c26014e..acafbb1cd 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -34,7 +34,6 @@ use ethcore::state::StateInfo; use ethcore_logger::RotatingLogger; use node_health::{NodeHealth, Health}; use updater::{Service as UpdateService}; - use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::{future, Future}; use jsonrpc_macros::Trailing; @@ -53,7 +52,7 @@ use v1::types::{ use Host; /// Parity implementation. -pub struct ParityClient { +pub struct ParityClient { client: Arc, miner: Arc, updater: Arc, @@ -143,11 +142,11 @@ impl Parity for ParityClient where .collect() ) } - + fn locked_hardware_accounts_info(&self) -> Result> { self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } - + fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); @@ -312,9 +311,9 @@ impl Parity for ParityClient where ); Ok(ready_transactions - .into_iter() - .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) - .collect() + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() ) } @@ -323,9 +322,9 @@ impl Parity for ParityClient where let all_transactions = self.miner.queued_transactions(); Ok(all_transactions - .into_iter() - .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) - .collect() + .into_iter() + .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) + .collect() ) } @@ -336,8 +335,8 @@ impl Parity for ParityClient where fn pending_transactions_stats(&self) -> Result> { let stats = self.sync.transactions_stats(); Ok(stats.into_iter() - .map(|(hash, stats)| (hash.into(), stats.into())) - .collect() + .map(|(hash, stats)| (hash.into(), stats.into())) + .collect() ) } @@ -345,9 +344,9 @@ impl Parity for ParityClient where let transactions = self.miner.local_transactions(); let block_number = self.client.chain_info().best_block_number; Ok(transactions - .into_iter() - .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition))) - .collect() + .into_iter() + .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition))) + .collect() ) } diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index 5a9aef3ba..f9be594ad 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -22,7 +22,6 @@ use ethereum_types::Address; use ethkey::{Brain, Generator, Secret}; use ethstore::KeyFile; use ethcore::account_provider::AccountProvider; - use jsonrpc_core::Result; use v1::helpers::errors; use v1::traits::ParityAccounts; diff --git a/util/fake-hardware-wallet/Cargo.toml b/util/fake-hardware-wallet/Cargo.toml new file mode 100644 index 000000000..600cd098c --- /dev/null +++ b/util/fake-hardware-wallet/Cargo.toml @@ -0,0 +1,10 @@ +[package] +description = "Fake hardware-wallet, for OS' that don't support libusb" +name = "fake-hardware-wallet" +version = "0.0.1" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[dependencies] +ethereum-types = "0.3" +ethkey = { path = "../../ethkey" } diff --git a/util/fake-hardware-wallet/src/lib.rs b/util/fake-hardware-wallet/src/lib.rs new file mode 100644 index 000000000..2bf905d7b --- /dev/null +++ b/util/fake-hardware-wallet/src/lib.rs @@ -0,0 +1,101 @@ +// Copyright 2015-2018 Parity Technologies (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 . + +//! Dummy module for platforms that does not provide support for hardware wallets (libusb) + +extern crate ethereum_types; +extern crate ethkey; + +use std::fmt; +use ethereum_types::U256; +use ethkey::{Address, Signature}; + +pub struct WalletInfo { + pub address: Address, + pub name: String, + pub manufacturer: String, +} + +#[derive(Debug)] +/// `ErrorType` for devices with no `hardware wallet` +pub enum Error { + NoWallet, + KeyNotFound, +} + +pub struct TransactionInfo { + /// Nonce + pub nonce: U256, + /// Gas price + pub gas_price: U256, + /// Gas limit + pub gas_limit: U256, + /// Receiver + pub to: Option
, + /// Value + pub value: U256, + /// Data + pub data: Vec, + /// Chain ID + pub chain_id: Option, +} + +pub enum KeyPath { + /// Ethereum. + Ethereum, + /// Ethereum classic. + EthereumClassic, +} + +/// `HardwareWalletManager` for devices with no `hardware wallet` +pub struct HardwareWalletManager; + +impl HardwareWalletManager { + pub fn new() -> Result { + Err(Error::NoWallet) + } + + pub fn set_key_path(&self, _key_path: KeyPath) {} + + pub fn wallet_info(&self, _: &Address) -> Option { + None + } + + pub fn list_wallets(&self) -> Vec { + Vec::with_capacity(0) + } + + pub fn list_locked_wallets(&self) -> Result, Error> { + Err(Error::NoWallet) + } + + pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result { + Err(Error::NoWallet) + } + + pub fn sign_transaction(&self, _address: &Address, _transaction: &TransactionInfo, _rlp_transaction: &[u8]) -> Result { + Err(Error::NoWallet) } + + pub fn sign_message(&self, _address: &Address, _msg: &[u8]) -> Result { + Err(Error::NoWallet) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "No hardware wallet!!") + } +}