From 5ab63252116a8e3fc80b15fc3bb791c06b2f0a65 Mon Sep 17 00:00:00 2001 From: niklasad1 Date: Mon, 23 Apr 2018 18:00:11 +0200 Subject: [PATCH 1/8] disable hardware-wallets that don't support libusb --- ethcore/src/account_provider/mod.rs | 60 +++++++++++++++++++- ethcore/src/lib.rs | 9 ++- rpc/src/lib.rs | 3 + rpc/src/v1/helpers/dispatch.rs | 85 ++++++++++++++++++++++++++++- rpc/src/v1/impls/light/parity.rs | 17 ++++++ rpc/src/v1/impls/parity.rs | 18 +++++- rpc/src/v1/impls/parity_accounts.rs | 11 +++- 7 files changed, 194 insertions(+), 9 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index a12aec8676b..0ff020a0808 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -31,11 +31,15 @@ use ethstore::{ 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}; + pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +use super::transaction::{Action, Transaction}; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; + /// Type of unlock. #[derive(Clone, PartialEq)] enum Unlock { @@ -63,6 +67,7 @@ pub enum SignError { /// Account does not exist. NotFound, /// Low-level hardware device error. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] Hardware(HardwareError), /// Low-level error from store SStore(SSError), @@ -73,12 +78,14 @@ impl fmt::Display for SignError { match *self { SignError::NotUnlocked => write!(f, "Account is locked"), SignError::NotFound => write!(f, "Account does not exist"), + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] SignError::Hardware(ref e) => write!(f, "{}", e), SignError::SStore(ref e) => write!(f, "{}", e), } } } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] impl From for SignError { fn from(e: HardwareError) -> Self { SignError::Hardware(e) @@ -130,6 +137,7 @@ pub struct AccountProvider { /// Accounts unlocked with rolling tokens transient_sstore: EthMultiStore, /// Accounts in hardware wallets. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] hardware_store: Option, /// When unlocking account permanently we additionally keep a raw secret in memory /// to increase the performance of transaction signing. @@ -163,8 +171,10 @@ impl Default for AccountProviderSettings { impl AccountProvider { /// Creates new account provider. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; + if settings.enable_hardware_wallets { match HardwareWalletManager::new() { Ok(manager) => { @@ -201,6 +211,34 @@ impl AccountProvider { } } + /// Creates new account provider without a hardware-wallet + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { + if let Ok(accounts) = sstore.accounts() { + for account in accounts.into_iter().filter(|a| settings.blacklisted_accounts.contains(&a.address)) { + warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored", + account.address); + } + } + + // Remove blacklisted accounts from address book. + let mut address_book = AddressBook::new(&sstore.local_path()); + for addr in &settings.blacklisted_accounts { + address_book.remove(*addr); + } + + AccountProvider { + unlocked_secrets: RwLock::new(HashMap::new()), + unlocked: RwLock::new(HashMap::new()), + address_book: RwLock::new(address_book), + dapps_settings: RwLock::new(DappsSettingsStore::new(&sstore.local_path())), + sstore: sstore, + transient_sstore: transient_sstore(), + unlock_keep_secret: settings.unlock_keep_secret, + blacklisted_accounts: settings.blacklisted_accounts, + } + } + /// Creates not disk backed provider. pub fn transient_provider() -> Self { AccountProvider { @@ -210,6 +248,7 @@ impl AccountProvider { dapps_settings: RwLock::new(DappsSettingsStore::transient()), sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")), transient_sstore: transient_sstore(), + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] hardware_store: None, unlock_keep_secret: false, blacklisted_accounts: vec![], @@ -288,12 +327,14 @@ impl AccountProvider { } /// Returns addresses of hardware accounts. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] 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()) } /// Get a list of paths to locked hardware wallets + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn locked_hardware_accounts(&self) -> Result, SignError> { match self.hardware_store.as_ref().map(|h| h.list_locked_wallets()) { None => Err(SignError::NotFound), @@ -303,6 +344,7 @@ impl AccountProvider { } /// Provide a pin to a locked hardware wallet on USB path to unlock it + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] 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)) { None => Err(SignError::NotFound), @@ -511,6 +553,7 @@ impl AccountProvider { } /// Returns each hardware account along with name and meta. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn hardware_accounts_info(&self) -> Result, Error> { let r = self.hardware_accounts()? .into_iter() @@ -520,11 +563,13 @@ impl AccountProvider { } /// Returns each hardware account along with name and meta. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn is_hardware_address(&self, address: &Address) -> bool { self.hardware_store.as_ref().and_then(|s| s.wallet_info(address)).is_some() } /// Returns each account along with name and meta. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn account_meta(&self, address: Address) -> Result { if let Some(info) = self.hardware_store.as_ref().and_then(|s| s.wallet_info(&address)) { Ok(AccountMeta { @@ -542,6 +587,17 @@ impl AccountProvider { } } + /// Returns each account along with name and meta without a hardware-wallet + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + pub fn account_meta(&self, address: Address) -> Result { + let account = self.sstore.account_ref(&address)?; + Ok(AccountMeta { + name: self.sstore.name(&account)?, + meta: self.sstore.meta(&account)?, + uuid: self.sstore.uuid(&account).ok().map(Into::into), // allowed to not have a Uuid + }) + } + /// Returns account public key. pub fn account_public(&self, address: Address, password: &Password) -> Result { self.sstore.public(&self.sstore.account_ref(&address)?, password) diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 274d52b247c..087da63298c 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -75,7 +75,8 @@ 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 +100,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; @@ -109,6 +109,11 @@ extern crate vm; extern crate wasm; extern crate memory_cache; extern crate journaldb; + +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +extern crate hardware_wallet; + +#[cfg(test)] extern crate tempdir; #[macro_use] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 2d49a8c7717..54784a9a1db 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -67,7 +67,10 @@ extern crate parity_version as version; extern crate rlp; extern crate stats; extern crate keccak_hash as hash; + +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; + extern crate patricia_trie as trie; #[macro_use] diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index b0e69edfb7a..d59b0e3bdc1 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; @@ -53,6 +52,9 @@ use v1::types::{ DecryptRequest as RpcDecryptRequest, }; +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +use rlp; + pub use self::nonce::Reservations; /// Has the capability to dispatch, sign, and decrypt. @@ -323,7 +325,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())) } } } @@ -418,6 +420,7 @@ impl Dispatcher for LightDispatcher { } } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn sign_transaction( accounts: &AccountProvider, filled: FilledTransactionRequest, @@ -447,6 +450,32 @@ fn sign_transaction( })) } +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +fn sign_transaction( + accounts: &AccountProvider, + filled: FilledTransactionRequest, + chain_id: Option, + nonce: U256, + password: SignWith, +) -> Result> { + let t = Transaction { + nonce: nonce, + action: filled.to.map_or(Action::Create, Action::Call), + gas: filled.gas, + gas_price: filled.gas_price, + value: filled.value, + data: filled.data, + }; + + let hash = t.hash(chain_id); + let signature = signature(accounts, filled.from, hash, password)?; + + Ok(signature.map(|sig| { + SignedTransaction::new(t.with_signature(sig, chain_id)) + .expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed") + })) +} + #[derive(Debug, Clone, Copy)] enum ProspectiveSignerState { TryProspectiveSign, @@ -647,6 +676,7 @@ impl From<(T, Option)> for WithToken { } /// Execute a confirmation payload. +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn execute( dispatcher: D, accounts: Arc, @@ -710,6 +740,56 @@ pub fn execute( } } +/// Execute a confirmation payload without a hardware wallet +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +pub fn execute( + dispatcher: D, + accounts: Arc, + payload: ConfirmationPayload, + pass: SignWith +) -> BoxFuture> { + match payload { + ConfirmationPayload::SendTransaction(request) => { + let condition = request.condition.clone().map(Into::into); + Box::new(dispatcher.sign(accounts, request, pass) + .map(move |v| v.map(move |tx| PendingTransaction::new(tx, condition))) + .map(WithToken::into_tuple) + .map(|(tx, token)| (tx, token, dispatcher)) + .and_then(|(tx, tok, dispatcher)| { + dispatcher.dispatch_transaction(tx) + .map(RpcH256::from) + .map(ConfirmationResponse::SendTransaction) + .map(move |h| WithToken::from((h, tok))) + })) + }, + ConfirmationPayload::SignTransaction(request) => { + Box::new(dispatcher.sign(accounts, request, pass) + .map(move |result| result + .map(move |tx| dispatcher.enrich(tx)) + .map(ConfirmationResponse::SignTransaction) + )) + }, + ConfirmationPayload::EthSignMessage(address, data) => { + let hash = eth_data_hash(data); + let res = signature(&accounts, address, hash, pass) + .map(|result| result + .map(|rsv| H520(rsv.into_electrum())) + .map(RpcH520::from) + .map(ConfirmationResponse::Signature) + ); + Box::new(future::done(res)) + }, + ConfirmationPayload::Decrypt(address, data) => { + let res = decrypt(&accounts, address, data, pass) + .map(|result| result + .map(RpcBytes) + .map(ConfirmationResponse::Decrypt) + ); + Box::new(future::done(res)) + }, + } +} + fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: SignWith) -> Result> { match password.clone() { SignWith::Nothing => accounts.sign(address, None, hash).map(WithToken::No), @@ -722,6 +802,7 @@ fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: } // obtain a hardware signature from the given account. +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, chain_id: Option) -> Result { diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 6e93132b922..20665de6254 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -49,6 +49,9 @@ use v1::types::{ }; use Host; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +use jsonrpc_core::Error; + /// Parity implementation for light client. pub struct ParityClient { client: Arc, @@ -130,6 +133,7 @@ impl Parity for ParityClient { ) } + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let store = &self.accounts; let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; @@ -140,11 +144,24 @@ impl Parity for ParityClient { ) } + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + // `unimplemented`, workaround to get it to compile because the trait requires this method + fn hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) + } + + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn locked_hardware_accounts_info(&self) -> Result> { let store = &self.accounts; Ok(store.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) } + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + // `unimplemented`, workaround to get it to compile because the trait requires this method + fn locked_hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) + } + fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); Ok(self.accounts diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index d7c26014edd..c4831c47d5e 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; @@ -52,6 +51,9 @@ use v1::types::{ }; use Host; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +use jsonrpc_core::Error; + /// Parity implementation. pub struct ParityClient { client: Arc, @@ -135,6 +137,7 @@ impl Parity for ParityClient where ) } + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info @@ -143,12 +146,23 @@ impl Parity for ParityClient where .collect() ) } + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + fn hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) + } + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] 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 { + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + fn locked_hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) + } + + fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); Ok(self.accounts diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index 5a9aef3bafc..048a5ec739d 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -22,13 +22,15 @@ 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; use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash, ExtAccountInfo}; use ethkey::Password; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +use jsonrpc_core::Error; + /// Account management (personal) rpc implementation. pub struct ParityAccountsClient { accounts: Arc, @@ -318,9 +320,16 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not sign message.", e)) } + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_pin_matrix_ack(&self, path: String, pin: String) -> Result { self.accounts.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + // Dummy implementation for builds that don't support `libusb` + fn hardware_pin_matrix_ack(&self, _path: String, _pin: String) -> Result { + Err(Error::parse_error()) + } } fn into_vec(a: Vec) -> Vec where From 9dbf0d9b6eaec92e40cb91647e7f95c64e0680bf Mon Sep 17 00:00:00 2001 From: niklasad1 Date: Sun, 13 May 2018 22:51:29 +0200 Subject: [PATCH 2/8] address grumbles --- ethcore/src/account_provider/mod.rs | 33 ++++++++++++++++------- ethcore/src/lib.rs | 3 +++ rpc/src/v1/helpers/dispatch.rs | 4 +-- rpc/src/v1/impls/light/parity.rs | 4 +-- rpc/src/v1/impls/parity.rs | 42 ++++++++++++++--------------- 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 0ff020a0808..1e42ff65773 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -31,14 +31,32 @@ use ethstore::{ use ethstore::accounts_dir::MemoryDirectory; use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; use ethjson::misc::AccountMeta; +use self::hw::*; pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] -use super::transaction::{Action, Transaction}; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] -use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; +mod hw { + pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; + pub use ::transaction::{Action, Transaction}; +} + +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] +mod hw { + use super::fmt; + + #[derive(Debug)] + pub enum HardwareError {} + pub struct HardwareWalletManager; + + impl fmt::Display for HardwareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "") + } + } +} + /// Type of unlock. #[derive(Clone, PartialEq)] @@ -67,7 +85,6 @@ pub enum SignError { /// Account does not exist. NotFound, /// Low-level hardware device error. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] Hardware(HardwareError), /// Low-level error from store SStore(SSError), @@ -78,14 +95,12 @@ impl fmt::Display for SignError { match *self { SignError::NotUnlocked => write!(f, "Account is locked"), SignError::NotFound => write!(f, "Account does not exist"), - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] SignError::Hardware(ref e) => write!(f, "{}", e), SignError::SStore(ref e) => write!(f, "{}", e), } } } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] impl From for SignError { fn from(e: HardwareError) -> Self { SignError::Hardware(e) @@ -137,7 +152,6 @@ pub struct AccountProvider { /// Accounts unlocked with rolling tokens transient_sstore: EthMultiStore, /// Accounts in hardware wallets. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] hardware_store: Option, /// When unlocking account permanently we additionally keep a raw secret in memory /// to increase the performance of transaction signing. @@ -216,8 +230,7 @@ impl AccountProvider { pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { if let Ok(accounts) = sstore.accounts() { for account in accounts.into_iter().filter(|a| settings.blacklisted_accounts.contains(&a.address)) { - warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored", - account.address); + warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored", account.address); } } @@ -234,6 +247,7 @@ impl AccountProvider { dapps_settings: RwLock::new(DappsSettingsStore::new(&sstore.local_path())), sstore: sstore, transient_sstore: transient_sstore(), + hardware_store: None, unlock_keep_secret: settings.unlock_keep_secret, blacklisted_accounts: settings.blacklisted_accounts, } @@ -248,7 +262,6 @@ impl AccountProvider { dapps_settings: RwLock::new(DappsSettingsStore::transient()), sstore: Box::new(EthStore::open(Box::new(MemoryDirectory::default())).expect("MemoryDirectory load always succeeds; qed")), transient_sstore: transient_sstore(), - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] hardware_store: None, unlock_keep_secret: false, blacklisted_accounts: vec![], diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 087da63298c..16d93e43c93 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -159,6 +159,9 @@ pub mod snapshot; pub mod spec; pub mod state; pub mod state_db; + +// Test helpers made public for usage outside ethcore +pub mod test_helpers; pub mod trace; pub mod verification; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index d59b0e3bdc1..4d5b980646c 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -818,8 +818,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 20665de6254..2987ce0c67e 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -322,8 +322,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 c4831c47d5e..6f3f6728e42 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -55,7 +55,7 @@ use Host; use jsonrpc_core::Error; /// Parity implementation. -pub struct ParityClient { +pub struct ParityClient { client: Arc, miner: Arc, updater: Arc, @@ -137,7 +137,7 @@ impl Parity for ParityClient where ) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info @@ -146,23 +146,23 @@ impl Parity for ParityClient where .collect() ) } - - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - fn hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + fn hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn locked_hardware_accounts_info(&self) -> Result> { self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] fn locked_hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) + Err(Error::parse_error()) } - fn default_account(&self, meta: Self::Metadata) -> Result { + fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); Ok(self.accounts @@ -326,9 +326,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() ) } @@ -337,9 +337,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() ) } @@ -350,8 +350,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() ) } @@ -359,9 +359,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() ) } From ee51d6d941b3b5984eaca0d28c25a57419b12fce Mon Sep 17 00:00:00 2001 From: niklasad1 Date: Fri, 1 Jun 2018 10:26:03 +0200 Subject: [PATCH 3/8] nits --- ethcore/src/account_provider/mod.rs | 73 ++++++++-------------- rpc/src/v1/helpers/dispatch.rs | 93 ++++------------------------- rpc/src/v1/impls/parity.rs | 10 ++-- 3 files changed, 40 insertions(+), 136 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 1e42ff65773..fd7eca9b62e 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -18,20 +18,20 @@ mod stores; -use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; - -use std::fmt; -use std::collections::{HashMap, HashSet}; -use std::time::{Instant, Duration}; -use parking_lot::RwLock; use ethstore::{ SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, }; +use ethjson::misc::AccountMeta; use ethstore::accounts_dir::MemoryDirectory; use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; use ethjson::misc::AccountMeta; +use parking_lot::RwLock; use self::hw::*; +use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; +use std::collections::{HashMap, HashSet}; +use std::fmt; +use std::time::{Instant, Duration}; pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; @@ -47,7 +47,11 @@ mod hw { use super::fmt; #[derive(Debug)] - pub enum HardwareError {} + /// `ErrorType` for devices with no `hardware wallet` + pub enum HardwareError { + NoWallet, + } + /// `HardwareWalletManager` for devices with no `hardware wallet` pub struct HardwareWalletManager; impl fmt::Display for HardwareError { @@ -57,7 +61,6 @@ mod hw { } } - /// Type of unlock. #[derive(Clone, PartialEq)] enum Unlock { @@ -185,17 +188,19 @@ impl Default for AccountProviderSettings { impl AccountProvider { /// Creates new account provider. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; - if settings.enable_hardware_wallets { - match HardwareWalletManager::new() { - Ok(manager) => { - manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum }); - hardware_store = Some(manager) - }, - Err(e) => debug!("Error initializing hardware wallets: {}", e), + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + { + if settings.enable_hardware_wallets { + match HardwareWalletManager::new() { + Ok(manager) => { + manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum }); + hardware_store = Some(manager) + }, + Err(e) => debug!("Error initializing hardware wallets: {}", e), + } } } @@ -225,34 +230,6 @@ impl AccountProvider { } } - /// Creates new account provider without a hardware-wallet - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { - if let Ok(accounts) = sstore.accounts() { - for account in accounts.into_iter().filter(|a| settings.blacklisted_accounts.contains(&a.address)) { - warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored", account.address); - } - } - - // Remove blacklisted accounts from address book. - let mut address_book = AddressBook::new(&sstore.local_path()); - for addr in &settings.blacklisted_accounts { - address_book.remove(*addr); - } - - AccountProvider { - unlocked_secrets: RwLock::new(HashMap::new()), - unlocked: RwLock::new(HashMap::new()), - address_book: RwLock::new(address_book), - dapps_settings: RwLock::new(DappsSettingsStore::new(&sstore.local_path())), - sstore: sstore, - transient_sstore: transient_sstore(), - hardware_store: None, - unlock_keep_secret: settings.unlock_keep_secret, - blacklisted_accounts: settings.blacklisted_accounts, - } - } - /// Creates not disk backed provider. pub fn transient_provider() -> Self { AccountProvider { @@ -340,12 +317,12 @@ impl AccountProvider { } /// Returns addresses of hardware accounts. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn hardware_accounts(&self) -> Result, Error> { - let accounts = self.hardware_store.as_ref().map_or(Vec::new(), |h| h.list_wallets()); + let accounts = self.hardware_store.as_ref().map_or_else(|| Vec::new(), |h| h.list_wallets()); Ok(accounts.into_iter().map(|a| a.address).collect()) } - + /// Get a list of paths to locked hardware wallets #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn locked_hardware_accounts(&self) -> Result, SignError> { @@ -355,7 +332,7 @@ impl AccountProvider { Some(Ok(s)) => Ok(s), } } - + /// Provide a pin to a locked hardware wallet on USB path to unlock it #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn hardware_pin_matrix_ack(&self, path: &str, pin: &str) -> Result { diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 4d5b980646c..5799912f831 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -420,7 +420,6 @@ impl Dispatcher for LightDispatcher { } } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn sign_transaction( accounts: &AccountProvider, filled: FilledTransactionRequest, @@ -437,8 +436,11 @@ fn sign_transaction( data: filled.data, }; - if accounts.is_hardware_address(&filled.from) { - return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + { + if accounts.is_hardware_address(&filled.from) { + return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) + } } let hash = t.hash(chain_id); @@ -450,32 +452,6 @@ fn sign_transaction( })) } -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -fn sign_transaction( - accounts: &AccountProvider, - filled: FilledTransactionRequest, - chain_id: Option, - nonce: U256, - password: SignWith, -) -> Result> { - let t = Transaction { - nonce: nonce, - action: filled.to.map_or(Action::Create, Action::Call), - gas: filled.gas, - gas_price: filled.gas_price, - value: filled.value, - data: filled.data, - }; - - let hash = t.hash(chain_id); - let signature = signature(accounts, filled.from, hash, password)?; - - Ok(signature.map(|sig| { - SignedTransaction::new(t.with_signature(sig, chain_id)) - .expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed") - })) -} - #[derive(Debug, Clone, Copy)] enum ProspectiveSignerState { TryProspectiveSign, @@ -676,7 +652,6 @@ impl From<(T, Option)> for WithToken { } /// Execute a confirmation payload. -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn execute( dispatcher: D, accounts: Arc, @@ -726,60 +701,12 @@ pub fn execute( Box::new(future::done(res)) }, ConfirmationPayload::Decrypt(address, data) => { - if accounts.is_hardware_address(&address) { - return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None))); + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + { + 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) - .map(ConfirmationResponse::Decrypt) - ); - Box::new(future::done(res)) - }, - } -} - -/// Execute a confirmation payload without a hardware wallet -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -pub fn execute( - dispatcher: D, - accounts: Arc, - payload: ConfirmationPayload, - pass: SignWith -) -> BoxFuture> { - match payload { - ConfirmationPayload::SendTransaction(request) => { - let condition = request.condition.clone().map(Into::into); - Box::new(dispatcher.sign(accounts, request, pass) - .map(move |v| v.map(move |tx| PendingTransaction::new(tx, condition))) - .map(WithToken::into_tuple) - .map(|(tx, token)| (tx, token, dispatcher)) - .and_then(|(tx, tok, dispatcher)| { - dispatcher.dispatch_transaction(tx) - .map(RpcH256::from) - .map(ConfirmationResponse::SendTransaction) - .map(move |h| WithToken::from((h, tok))) - })) - }, - ConfirmationPayload::SignTransaction(request) => { - Box::new(dispatcher.sign(accounts, request, pass) - .map(move |result| result - .map(move |tx| dispatcher.enrich(tx)) - .map(ConfirmationResponse::SignTransaction) - )) - }, - ConfirmationPayload::EthSignMessage(address, data) => { - let hash = eth_data_hash(data); - let res = signature(&accounts, address, hash, pass) - .map(|result| result - .map(|rsv| H520(rsv.into_electrum())) - .map(RpcH520::from) - .map(ConfirmationResponse::Signature) - ); - Box::new(future::done(res)) - }, - ConfirmationPayload::Decrypt(address, data) => { let res = decrypt(&accounts, address, data, pass) .map(|result| result .map(RpcBytes) diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 6f3f6728e42..ad21dfe995d 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -137,7 +137,7 @@ impl Parity for ParityClient where ) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info @@ -147,10 +147,10 @@ impl Parity for ParityClient where ) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - fn hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) - } + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] + fn hardware_accounts_info(&self) -> Result> { + Err(Error::parse_error()) + } #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn locked_hardware_accounts_info(&self) -> Result> { From 52cef2d74ae0a4a3dc2866eee48e8e0922e0fdb8 Mon Sep 17 00:00:00 2001 From: Niklas Adofsson Date: Fri, 1 Jun 2018 17:48:41 +0200 Subject: [PATCH 4/8] Refactor to get rid off as much annotations asap * Might consume slight more memory than pure conditional compilation flags --- ethcore/src/account_provider/mod.rs | 63 ++++++++------------------- ethcore/src/account_provider/no_hw.rs | 42 ++++++++++++++++++ ethcore/src/lib.rs | 3 +- rpc/src/lib.rs | 2 +- rpc/src/v1/helpers/dispatch.rs | 13 +++--- rpc/src/v1/impls/light/parity.rs | 17 -------- rpc/src/v1/impls/parity.rs | 15 ------- rpc/src/v1/impls/parity_accounts.rs | 10 ----- 8 files changed, 66 insertions(+), 99 deletions(-) create mode 100644 ethcore/src/account_provider/no_hw.rs diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index fd7eca9b62e..76ce68a3b61 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -18,6 +18,9 @@ mod stores; +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] +mod no_hw; + use ethstore::{ SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, @@ -27,7 +30,6 @@ use ethstore::accounts_dir::MemoryDirectory; use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; use ethjson::misc::AccountMeta; use parking_lot::RwLock; -use self::hw::*; use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; use std::collections::{HashMap, HashSet}; use std::fmt; @@ -35,30 +37,16 @@ use std::time::{Instant, Duration}; pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; +pub use super::transaction::{Action, Transaction}; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] mod hw { pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; - pub use ::transaction::{Action, Transaction}; } -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -mod hw { - use super::fmt; - - #[derive(Debug)] - /// `ErrorType` for devices with no `hardware wallet` - pub enum HardwareError { - NoWallet, - } - /// `HardwareWalletManager` for devices with no `hardware wallet` - pub struct HardwareWalletManager; - - impl fmt::Display for HardwareError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "") - } - } +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] +mod hw { + pub use account_provider::no_hw::{HardwareError, HardwareWalletManager}; } /// Type of unlock. @@ -88,7 +76,7 @@ pub enum SignError { /// Account does not exist. NotFound, /// Low-level hardware device error. - Hardware(HardwareError), + Hardware(hw::HardwareError), /// Low-level error from store SStore(SSError), } @@ -104,8 +92,8 @@ impl fmt::Display for SignError { } } -impl From for SignError { - fn from(e: HardwareError) -> Self { +impl From for SignError { + fn from(e: hw::HardwareError) -> Self { SignError::Hardware(e) } } @@ -155,7 +143,7 @@ pub struct AccountProvider { /// Accounts unlocked with rolling tokens transient_sstore: EthMultiStore, /// Accounts in hardware wallets. - hardware_store: Option, + hardware_store: Option, /// When unlocking account permanently we additionally keep a raw secret in memory /// to increase the performance of transaction signing. unlock_keep_secret: bool, @@ -191,12 +179,12 @@ impl AccountProvider { pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] { if settings.enable_hardware_wallets { - match HardwareWalletManager::new() { + match hw::HardwareWalletManager::new() { Ok(manager) => { - manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum }); + manager.set_key_path(if settings.hardware_wallet_classic_key { hw::KeyPath::EthereumClassic } else { hw::KeyPath::Ethereum }); hardware_store = Some(manager) }, Err(e) => debug!("Error initializing hardware wallets: {}", e), @@ -317,14 +305,12 @@ impl AccountProvider { } /// Returns addresses of hardware accounts. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn hardware_accounts(&self) -> Result, Error> { let accounts = self.hardware_store.as_ref().map_or_else(|| Vec::new(), |h| h.list_wallets()); Ok(accounts.into_iter().map(|a| a.address).collect()) } - + /// Get a list of paths to locked hardware wallets - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn locked_hardware_accounts(&self) -> Result, SignError> { match self.hardware_store.as_ref().map(|h| h.list_locked_wallets()) { None => Err(SignError::NotFound), @@ -334,7 +320,6 @@ impl AccountProvider { } /// Provide a pin to a locked hardware wallet on USB path to unlock it - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] 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)) { None => Err(SignError::NotFound), @@ -543,7 +528,6 @@ impl AccountProvider { } /// Returns each hardware account along with name and meta. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn hardware_accounts_info(&self) -> Result, Error> { let r = self.hardware_accounts()? .into_iter() @@ -553,13 +537,11 @@ impl AccountProvider { } /// Returns each hardware account along with name and meta. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn is_hardware_address(&self, address: &Address) -> bool { self.hardware_store.as_ref().and_then(|s| s.wallet_info(address)).is_some() } /// Returns each account along with name and meta. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] pub fn account_meta(&self, address: Address) -> Result { if let Some(info) = self.hardware_store.as_ref().and_then(|s| s.wallet_info(&address)) { Ok(AccountMeta { @@ -577,17 +559,6 @@ impl AccountProvider { } } - /// Returns each account along with name and meta without a hardware-wallet - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - pub fn account_meta(&self, address: Address) -> Result { - let account = self.sstore.account_ref(&address)?; - Ok(AccountMeta { - name: self.sstore.name(&account)?, - meta: self.sstore.meta(&account)?, - uuid: self.sstore.uuid(&account).ok().map(Into::into), // allowed to not have a Uuid - }) - } - /// Returns account public key. pub fn account_public(&self, address: Address, password: &Password) -> Result { self.sstore.public(&self.sstore.account_ref(&address)?, password) @@ -879,7 +850,7 @@ impl AccountProvider { chain_id: chain_id, }; match self.hardware_store.as_ref().map(|s| s.sign_transaction(&address, &t_info, rlp_encoded_transaction)) { - None | Some(Err(HardwareError::KeyNotFound)) => Err(SignError::NotFound), + None | Some(Err(hw::HardwareError::KeyNotFound)) => Err(SignError::NotFound), Some(Err(e)) => Err(From::from(e)), Some(Ok(s)) => Ok(s), } diff --git a/ethcore/src/account_provider/no_hw.rs b/ethcore/src/account_provider/no_hw.rs new file mode 100644 index 00000000000..b15d1c8244c --- /dev/null +++ b/ethcore/src/account_provider/no_hw.rs @@ -0,0 +1,42 @@ +//! Dummy module for platforms that does not provide support for hardware wallets (libusb) + +use super::{fmt, Address}; + +pub struct WalletInfo { + pub address: Address, + pub name: String, + pub manufacturer: String, +} + +#[derive(Debug)] +/// `ErrorType` for devices with no `hardware wallet` +pub enum HardwareError { + NoWallet, +} + +/// `HardwareWalletManager` for devices with no `hardware wallet` +pub struct HardwareWalletManager; + +impl HardwareWalletManager { + 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, HardwareError> { + Err(HardwareError::NoWallet) + } + + pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result { + Err(HardwareError::NoWallet) + } +} + +impl fmt::Display for HardwareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "") + } +} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 16d93e43c93..582dbdf68be 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -76,7 +76,6 @@ extern crate ethereum_types; extern crate ethjson; extern crate ethkey; - extern crate hashdb; extern crate itertools; extern crate kvdb; @@ -110,7 +109,7 @@ extern crate wasm; extern crate memory_cache; extern crate journaldb; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] extern crate hardware_wallet; #[cfg(test)] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 54784a9a1db..78333a2bc3f 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -68,7 +68,7 @@ extern crate rlp; extern crate stats; extern crate keccak_hash as hash; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] extern crate hardware_wallet; extern crate patricia_trie as trie; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 5799912f831..17661bec6e1 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -52,7 +52,7 @@ use v1::types::{ DecryptRequest as RpcDecryptRequest, }; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] use rlp; pub use self::nonce::Reservations; @@ -436,7 +436,7 @@ fn sign_transaction( data: filled.data, }; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] { if accounts.is_hardware_address(&filled.from) { return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) @@ -701,11 +701,8 @@ pub fn execute( Box::new(future::done(res)) }, ConfirmationPayload::Decrypt(address, data) => { - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] - { - if accounts.is_hardware_address(&address) { - return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None))); - } + 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 @@ -729,7 +726,7 @@ fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: } // obtain a hardware signature from the given account. -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, chain_id: Option) -> Result { diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 2987ce0c67e..9ef316b70be 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -49,9 +49,6 @@ use v1::types::{ }; use Host; -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -use jsonrpc_core::Error; - /// Parity implementation for light client. pub struct ParityClient { client: Arc, @@ -133,7 +130,6 @@ impl Parity for ParityClient { ) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let store = &self.accounts; let info = store.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; @@ -144,24 +140,11 @@ impl Parity for ParityClient { ) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - // `unimplemented`, workaround to get it to compile because the trait requires this method - fn hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) - } - - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn locked_hardware_accounts_info(&self) -> Result> { let store = &self.accounts; Ok(store.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e))?) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - // `unimplemented`, workaround to get it to compile because the trait requires this method - fn locked_hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) - } - fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); Ok(self.accounts diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index ad21dfe995d..acafbb1cd68 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -51,9 +51,6 @@ use v1::types::{ }; use Host; -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -use jsonrpc_core::Error; - /// Parity implementation. pub struct ParityClient { client: Arc, @@ -137,7 +134,6 @@ impl Parity for ParityClient where ) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_accounts_info(&self) -> Result> { let info = self.accounts.hardware_accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?; Ok(info @@ -147,20 +143,9 @@ impl Parity for ParityClient where ) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - fn hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) - } - - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn locked_hardware_accounts_info(&self) -> Result> { self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } - - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - fn locked_hardware_accounts_info(&self) -> Result> { - Err(Error::parse_error()) - } fn default_account(&self, meta: Self::Metadata) -> Result { let dapp_id = meta.dapp_id(); diff --git a/rpc/src/v1/impls/parity_accounts.rs b/rpc/src/v1/impls/parity_accounts.rs index 048a5ec739d..f9be594ad8b 100644 --- a/rpc/src/v1/impls/parity_accounts.rs +++ b/rpc/src/v1/impls/parity_accounts.rs @@ -28,9 +28,6 @@ use v1::traits::ParityAccounts; use v1::types::{H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, DappId, Derive, DeriveHierarchical, DeriveHash, ExtAccountInfo}; use ethkey::Password; -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -use jsonrpc_core::Error; - /// Account management (personal) rpc implementation. pub struct ParityAccountsClient { accounts: Arc, @@ -320,16 +317,9 @@ impl ParityAccounts for ParityAccountsClient { .map_err(|e| errors::account("Could not sign message.", e)) } - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_pin_matrix_ack(&self, path: String, pin: String) -> Result { self.accounts.hardware_pin_matrix_ack(&path, &pin).map_err(|e| errors::account("Error communicating with hardware wallet.", e)) } - - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] - // Dummy implementation for builds that don't support `libusb` - fn hardware_pin_matrix_ack(&self, _path: String, _pin: String) -> Result { - Err(Error::parse_error()) - } } fn into_vec(a: Vec) -> Vec where From 3156280d48330e6b8451d970d3e88ca47bc7dc2e Mon Sep 17 00:00:00 2001 From: Niklas Adofsson Date: Sat, 2 Jun 2018 16:09:58 +0200 Subject: [PATCH 5/8] formatting nits --- ethcore/src/account_provider/no_hw.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/account_provider/no_hw.rs b/ethcore/src/account_provider/no_hw.rs index b15d1c8244c..9f65dd06c7a 100644 --- a/ethcore/src/account_provider/no_hw.rs +++ b/ethcore/src/account_provider/no_hw.rs @@ -19,7 +19,7 @@ pub struct HardwareWalletManager; impl HardwareWalletManager { pub fn wallet_info(&self, _: &Address) -> Option { - None + None } pub fn list_wallets(&self) -> Vec { @@ -27,11 +27,11 @@ impl HardwareWalletManager { } pub fn list_locked_wallets(&self) -> Result, HardwareError> { - Err(HardwareError::NoWallet) + Err(HardwareError::NoWallet) } pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result { - Err(HardwareError::NoWallet) + Err(HardwareError::NoWallet) } } From 950a54a40258d86ef58559b2046e36f7b01ba7b7 Mon Sep 17 00:00:00 2001 From: Niklas Adofsson Date: Sun, 3 Jun 2018 14:39:19 +0200 Subject: [PATCH 6/8] Enable libusb for android * Tested by it compiling succesfully with `cargo build --target=armv7--linux-androideabi` * The binary is ~66 MB ```bash $ size size target/armv7-linux-androideabi/release/parity text data bss dec hex filename 50676230 416200 31456 51123886 30c16ae target/armv7-linux-androideabi/release/parity ``` --- ethcore/src/account_provider/mod.rs | 8 ++++---- ethcore/src/lib.rs | 2 +- rpc/src/lib.rs | 2 +- rpc/src/v1/helpers/dispatch.rs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 76ce68a3b61..72b2ef5bebe 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -18,7 +18,7 @@ mod stores; -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] mod no_hw; use ethstore::{ @@ -39,12 +39,12 @@ pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; pub use super::transaction::{Action, Transaction}; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] mod hw { pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; } -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] +#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] mod hw { pub use account_provider::no_hw::{HardwareError, HardwareWalletManager}; } @@ -179,7 +179,7 @@ impl AccountProvider { pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] { if settings.enable_hardware_wallets { match hw::HardwareWalletManager::new() { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 582dbdf68be..e992f245328 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -109,7 +109,7 @@ extern crate wasm; extern crate memory_cache; extern crate journaldb; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; #[cfg(test)] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 78333a2bc3f..54784a9a1db 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -68,7 +68,7 @@ extern crate rlp; extern crate stats; extern crate keccak_hash as hash; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; extern crate patricia_trie as trie; diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 17661bec6e1..a34e2e61f39 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -52,7 +52,7 @@ use v1::types::{ DecryptRequest as RpcDecryptRequest, }; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] use rlp; pub use self::nonce::Reservations; @@ -436,7 +436,7 @@ fn sign_transaction( data: filled.data, }; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] { if accounts.is_hardware_address(&filled.from) { return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) @@ -726,7 +726,7 @@ fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: } // obtain a hardware signature from the given account. -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, chain_id: Option) -> Result { From 6548566610cac3166b4a157362f72230458e603c Mon Sep 17 00:00:00 2001 From: Niklas Adofsson Date: Fri, 15 Jun 2018 23:39:31 +0200 Subject: [PATCH 7/8] Move all `fake-hardware-wallet` to its own crate * Removes some conditional compilation flags * Introduces `fake-hardware-wallet` crate --- Cargo.lock | 10 +++ ethcore/Cargo.toml | 7 +- ethcore/src/account_provider/mod.rs | 41 ++++------- ethcore/src/account_provider/no_hw.rs | 42 ----------- ethcore/src/lib.rs | 4 +- rpc/Cargo.toml | 6 ++ rpc/src/lib.rs | 9 ++- rpc/src/v1/helpers/dispatch.rs | 10 +-- util/fake-hardware-wallet/Cargo.toml | 10 +++ util/fake-hardware-wallet/src/lib.rs | 101 ++++++++++++++++++++++++++ 10 files changed, 156 insertions(+), 84 deletions(-) delete mode 100644 ethcore/src/account_provider/no_hw.rs create mode 100644 util/fake-hardware-wallet/Cargo.toml create mode 100644 util/fake-hardware-wallet/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 80c31ce3378..83d6d0a9409 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,6 +537,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", @@ -1064,6 +1065,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" @@ -2230,6 +2239,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 fe05badb4a5..d02dbd8229f 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 = "0.3" 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 72b2ef5bebe..d4a5da49e98 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -18,9 +18,6 @@ mod stores; -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -mod no_hw; - use ethstore::{ SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, @@ -37,18 +34,9 @@ use std::time::{Instant, Duration}; 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}; -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] -mod hw { - pub use hardware_wallet::{Error as HardwareError, HardwareWalletManager, KeyPath, TransactionInfo}; -} - -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android")))] -mod hw { - pub use account_provider::no_hw::{HardwareError, HardwareWalletManager}; -} - /// Type of unlock. #[derive(Clone, PartialEq)] enum Unlock { @@ -76,7 +64,7 @@ pub enum SignError { /// Account does not exist. NotFound, /// Low-level hardware device error. - Hardware(hw::HardwareError), + Hardware(HardwareError), /// Low-level error from store SStore(SSError), } @@ -92,8 +80,8 @@ impl fmt::Display for SignError { } } -impl From for SignError { - fn from(e: hw::HardwareError) -> Self { +impl From for SignError { + fn from(e: HardwareError) -> Self { SignError::Hardware(e) } } @@ -143,7 +131,7 @@ pub struct AccountProvider { /// Accounts unlocked with rolling tokens transient_sstore: EthMultiStore, /// Accounts in hardware wallets. - hardware_store: Option, + hardware_store: Option, /// When unlocking account permanently we additionally keep a raw secret in memory /// to increase the performance of transaction signing. unlock_keep_secret: bool, @@ -179,16 +167,13 @@ impl AccountProvider { pub fn new(sstore: Box, settings: AccountProviderSettings) -> Self { let mut hardware_store = None; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] - { - if settings.enable_hardware_wallets { - match hw::HardwareWalletManager::new() { - Ok(manager) => { - manager.set_key_path(if settings.hardware_wallet_classic_key { hw::KeyPath::EthereumClassic } else { hw::KeyPath::Ethereum }); - hardware_store = Some(manager) - }, - Err(e) => debug!("Error initializing hardware wallets: {}", e), - } + if settings.enable_hardware_wallets { + match HardwareWalletManager::new() { + Ok(manager) => { + manager.set_key_path(if settings.hardware_wallet_classic_key { KeyPath::EthereumClassic } else { KeyPath::Ethereum }); + hardware_store = Some(manager) + }, + Err(e) => debug!("Error initializing hardware wallets: {}", e), } } @@ -850,7 +835,7 @@ impl AccountProvider { chain_id: chain_id, }; match self.hardware_store.as_ref().map(|s| s.sign_transaction(&address, &t_info, rlp_encoded_transaction)) { - None | Some(Err(hw::HardwareError::KeyNotFound)) => Err(SignError::NotFound), + None | Some(Err(HardwareError::KeyNotFound)) => Err(SignError::NotFound), Some(Err(e)) => Err(From::from(e)), Some(Ok(s)) => Ok(s), } diff --git a/ethcore/src/account_provider/no_hw.rs b/ethcore/src/account_provider/no_hw.rs deleted file mode 100644 index 9f65dd06c7a..00000000000 --- a/ethcore/src/account_provider/no_hw.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Dummy module for platforms that does not provide support for hardware wallets (libusb) - -use super::{fmt, Address}; - -pub struct WalletInfo { - pub address: Address, - pub name: String, - pub manufacturer: String, -} - -#[derive(Debug)] -/// `ErrorType` for devices with no `hardware wallet` -pub enum HardwareError { - NoWallet, -} - -/// `HardwareWalletManager` for devices with no `hardware wallet` -pub struct HardwareWalletManager; - -impl HardwareWalletManager { - 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, HardwareError> { - Err(HardwareError::NoWallet) - } - - pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result { - Err(HardwareError::NoWallet) - } -} - -impl fmt::Display for HardwareError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "") - } -} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index e992f245328..763043d62db 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -112,6 +112,9 @@ extern crate journaldb; #[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; + #[cfg(test)] extern crate tempdir; @@ -160,7 +163,6 @@ pub mod state; pub mod state_db; // Test helpers made public for usage outside ethcore -pub mod test_helpers; pub mod trace; pub mod verification; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index d227f45f535..8487844bd6f 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 54784a9a1db..6356dc28448 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -58,20 +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 a34e2e61f39..c6f10400a58 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -51,8 +51,6 @@ use v1::types::{ SignRequest as RpcSignRequest, DecryptRequest as RpcDecryptRequest, }; - -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] use rlp; pub use self::nonce::Reservations; @@ -436,11 +434,8 @@ fn sign_transaction( data: filled.data, }; - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] - { - if accounts.is_hardware_address(&filled.from) { - return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) - } + if accounts.is_hardware_address(&filled.from) { + return hardware_signature(accounts, filled.from, t, chain_id).map(WithToken::No) } let hash = t.hash(chain_id); @@ -726,7 +721,6 @@ fn signature(accounts: &AccountProvider, address: Address, hash: H256, password: } // obtain a hardware signature from the given account. -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transaction, chain_id: Option) -> Result { diff --git a/util/fake-hardware-wallet/Cargo.toml b/util/fake-hardware-wallet/Cargo.toml new file mode 100644 index 00000000000..600cd098c5d --- /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 00000000000..b00d1892ee8 --- /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, "") + } +} From 2011226214288000830d6490568966b0abd9dbf2 Mon Sep 17 00:00:00 2001 From: Niklas Adofsson Date: Sat, 16 Jun 2018 17:26:15 +0200 Subject: [PATCH 8/8] return error if no hardware wallets are found --- ethcore/src/account_provider/mod.rs | 25 +++++++++++++++---------- ethcore/src/lib.rs | 6 +----- util/fake-hardware-wallet/src/lib.rs | 8 ++++---- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index d4a5da49e98..e4289c60a57 100644 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -18,19 +18,20 @@ mod stores; +use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; + +use std::collections::{HashMap, HashSet}; +use std::fmt; +use std::time::{Instant, Duration}; + +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 ethjson::misc::AccountMeta; -use ethstore::accounts_dir::MemoryDirectory; -use ethstore::ethkey::{Address, Message, Public, Secret, Password, Random, Generator}; -use ethjson::misc::AccountMeta; use parking_lot::RwLock; -use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; -use std::collections::{HashMap, HashSet}; -use std::fmt; -use std::time::{Instant, Duration}; pub use ethstore::ethkey::Signature; pub use ethstore::{Derivation, IndexDerivation, KeyFile}; @@ -291,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_else(|| 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 diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 763043d62db..ee4980c0560 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -108,6 +108,7 @@ extern crate vm; extern crate wasm; extern crate memory_cache; extern crate journaldb; +extern crate tempdir; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))] extern crate hardware_wallet; @@ -115,9 +116,6 @@ 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; -#[cfg(test)] -extern crate tempdir; - #[macro_use] extern crate ethabi_derive; #[macro_use] @@ -161,8 +159,6 @@ pub mod snapshot; pub mod spec; pub mod state; pub mod state_db; - -// Test helpers made public for usage outside ethcore pub mod trace; pub mod verification; diff --git a/util/fake-hardware-wallet/src/lib.rs b/util/fake-hardware-wallet/src/lib.rs index b00d1892ee8..2bf905d7bf7 100644 --- a/util/fake-hardware-wallet/src/lib.rs +++ b/util/fake-hardware-wallet/src/lib.rs @@ -33,7 +33,7 @@ pub struct WalletInfo { /// `ErrorType` for devices with no `hardware wallet` pub enum Error { NoWallet, - KeyNotFound, + KeyNotFound, } pub struct TransactionInfo { @@ -65,8 +65,8 @@ pub struct HardwareWalletManager; impl HardwareWalletManager { pub fn new() -> Result { - Err(Error::NoWallet) - } + Err(Error::NoWallet) + } pub fn set_key_path(&self, _key_path: KeyPath) {} @@ -96,6 +96,6 @@ impl HardwareWalletManager { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "") + write!(f, "No hardware wallet!!") } }