Disable hardware-wallets on platforms that don't support libusb (#8464)

* disable hardware-wallets that don't support libusb

* address grumbles

* nits

* Refactor to get rid off as much annotations asap

* Might consume slight more memory than pure conditional compilation
flags

* formatting nits

* 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
```

* Move all `fake-hardware-wallet` to its own crate

* Removes some conditional compilation flags
* Introduces `fake-hardware-wallet` crate

* return error if no hardware wallets are found
This commit is contained in:
Niklas Adolfsson 2018-06-26 09:03:38 +02:00 committed by Afri Schoedon
parent 4145be863b
commit 1a16f335fa
12 changed files with 184 additions and 39 deletions

10
Cargo.lock generated
View File

@ -545,6 +545,7 @@ dependencies = [
"ethkey 0.3.0", "ethkey 0.3.0",
"ethstore 0.2.0", "ethstore 0.2.0",
"evm 0.1.0", "evm 0.1.0",
"fake-hardware-wallet 0.0.1",
"fetch 0.1.0", "fetch 0.1.0",
"hardware-wallet 1.12.0", "hardware-wallet 1.12.0",
"hashdb 0.1.1", "hashdb 0.1.1",
@ -1072,6 +1073,14 @@ dependencies = [
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "fdlimit" name = "fdlimit"
version = "0.1.1" version = "0.1.1"
@ -2238,6 +2247,7 @@ dependencies = [
"ethkey 0.3.0", "ethkey 0.3.0",
"ethstore 0.2.0", "ethstore 0.2.0",
"fake-fetch 0.0.1", "fake-fetch 0.0.1",
"fake-hardware-wallet 0.0.1",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -36,7 +36,6 @@ ethjson = { path = "../json" }
ethkey = { path = "../ethkey" } ethkey = { path = "../ethkey" }
ethstore = { path = "../ethstore" } ethstore = { path = "../ethstore" }
evm = { path = "evm" } evm = { path = "evm" }
hardware-wallet = { path = "../hw" }
heapsize = "0.4" heapsize = "0.4"
itertools = "0.5" itertools = "0.5"
lazy_static = "1.0" lazy_static = "1.0"
@ -70,6 +69,12 @@ journaldb = { path = "../util/journaldb" }
tempdir = { version = "0.3", optional = true } tempdir = { version = "0.3", optional = true }
kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } 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] [dev-dependencies]
trie-standardmap = { path = "../util/trie-standardmap" } trie-standardmap = { path = "../util/trie-standardmap" }

View File

@ -20,21 +20,23 @@ mod stores;
use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy}; use self::stores::{AddressBook, DappsSettingsStore, NewDappsPolicy};
use std::fmt;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt;
use std::time::{Instant, Duration}; 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::{ use ethstore::{
SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore, SimpleSecretStore, SecretStore, Error as SSError, EthStore, EthMultiStore,
random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret, random_string, SecretVaultRef, StoreAccountRef, OpaqueSecret,
}; };
use ethstore::accounts_dir::MemoryDirectory; use parking_lot::RwLock;
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::ethkey::Signature;
pub use ethstore::{Derivation, IndexDerivation, KeyFile}; 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. /// Type of unlock.
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
@ -165,6 +167,7 @@ impl AccountProvider {
/// Creates new account provider. /// Creates new account provider.
pub fn new(sstore: Box<SecretStore>, settings: AccountProviderSettings) -> Self { pub fn new(sstore: Box<SecretStore>, settings: AccountProviderSettings) -> Self {
let mut hardware_store = None; let mut hardware_store = None;
if settings.enable_hardware_wallets { if settings.enable_hardware_wallets {
match HardwareWalletManager::new() { match HardwareWalletManager::new() {
Ok(manager) => { Ok(manager) => {
@ -289,8 +292,12 @@ impl AccountProvider {
/// Returns addresses of hardware accounts. /// Returns addresses of hardware accounts.
pub fn hardware_accounts(&self) -> Result<Vec<Address>, Error> { pub fn hardware_accounts(&self) -> Result<Vec<Address>, Error> {
let accounts = self.hardware_store.as_ref().map_or(Vec::new(), |h| h.list_wallets()); if let Some(accounts) = self.hardware_store.as_ref().map(|h| h.list_wallets()) {
Ok(accounts.into_iter().map(|a| a.address).collect()) 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 /// Get a list of paths to locked hardware wallets
@ -301,7 +308,7 @@ impl AccountProvider {
Some(Ok(s)) => Ok(s), Some(Ok(s)) => Ok(s),
} }
} }
/// Provide a pin to a locked hardware wallet on USB path to unlock it /// 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<bool, SignError> { pub fn hardware_pin_matrix_ack(&self, path: &str, pin: &str) -> Result<bool, SignError> {
match self.hardware_store.as_ref().map(|h| h.pin_matrix_ack(path, pin)) { match self.hardware_store.as_ref().map(|h| h.pin_matrix_ack(path, pin)) {

View File

@ -75,7 +75,7 @@ extern crate ethcore_transaction as transaction;
extern crate ethereum_types; extern crate ethereum_types;
extern crate ethjson; extern crate ethjson;
extern crate ethkey; extern crate ethkey;
extern crate hardware_wallet;
extern crate hashdb; extern crate hashdb;
extern crate itertools; extern crate itertools;
extern crate kvdb; extern crate kvdb;
@ -99,7 +99,6 @@ extern crate ansi_term;
extern crate unexpected; extern crate unexpected;
extern crate util_error; extern crate util_error;
extern crate snappy; extern crate snappy;
extern crate ethabi; extern crate ethabi;
extern crate rustc_hex; extern crate rustc_hex;
extern crate stats; extern crate stats;
@ -112,6 +111,12 @@ extern crate journaldb;
#[cfg(any(test, feature = "json-tests", feature = "test-helpers"))] #[cfg(any(test, feature = "json-tests", feature = "test-helpers"))]
extern crate tempdir; 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] #[macro_use]
extern crate ethabi_derive; extern crate ethabi_derive;
#[macro_use] #[macro_use]

View File

@ -64,6 +64,12 @@ rlp = { path = "../util/rlp" }
stats = { path = "../util/stats" } stats = { path = "../util/stats" }
vm = { path = "../ethcore/vm" } 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] [dev-dependencies]
ethcore = { path = "../ethcore", features = ["test-helpers"] } ethcore = { path = "../ethcore", features = ["test-helpers"] }
ethcore-network = { path = "../util/network" } ethcore-network = { path = "../util/network" }

View File

@ -58,17 +58,21 @@ extern crate ethcore_transaction as transaction;
extern crate ethereum_types; extern crate ethereum_types;
extern crate ethkey; extern crate ethkey;
extern crate ethstore; extern crate ethstore;
extern crate vm;
extern crate fetch; extern crate fetch;
extern crate keccak_hash as hash;
extern crate node_health; extern crate node_health;
extern crate parity_reactor; extern crate parity_reactor;
extern crate parity_updater as updater; extern crate parity_updater as updater;
extern crate parity_version as version; extern crate parity_version as version;
extern crate patricia_trie as trie;
extern crate rlp; extern crate rlp;
extern crate stats; 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 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] #[macro_use]
extern crate log; extern crate log;

View File

@ -24,7 +24,6 @@ use light::cache::Cache as LightDataCache;
use light::client::LightChainClient; use light::client::LightChainClient;
use light::on_demand::{request, OnDemand}; use light::on_demand::{request, OnDemand};
use light::TransactionQueue as LightTransactionQueue; use light::TransactionQueue as LightTransactionQueue;
use rlp;
use hash::keccak; use hash::keccak;
use ethereum_types::{H256, H520, Address, U256}; use ethereum_types::{H256, H520, Address, U256};
use bytes::Bytes; use bytes::Bytes;
@ -52,6 +51,7 @@ use v1::types::{
SignRequest as RpcSignRequest, SignRequest as RpcSignRequest,
DecryptRequest as RpcDecryptRequest, DecryptRequest as RpcDecryptRequest,
}; };
use rlp;
pub use self::nonce::Reservations; pub use self::nonce::Reservations;
@ -323,7 +323,7 @@ impl LightDispatcher {
x.map(move |acc| acc.map_or(account_start_nonce, |acc| acc.nonce)) x.map(move |acc| acc.map_or(account_start_nonce, |acc| acc.nonce))
.map_err(|_| errors::no_light_peers()) .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<D: Dispatcher + 'static>(
if accounts.is_hardware_address(&address) { if accounts.is_hardware_address(&address) {
return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None))); return Box::new(future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None)));
} }
let res = decrypt(&accounts, address, data, pass) let res = decrypt(&accounts, address, data, pass)
.map(|result| result .map(|result| result
.map(RpcBytes) .map(RpcBytes)
@ -737,8 +736,8 @@ fn hardware_signature(accounts: &AccountProvider, address: Address, t: Transacti
SignedTransaction::new(t.with_signature(signature, chain_id)) SignedTransaction::new(t.with_signature(signature, chain_id))
.map_err(|e| { .map_err(|e| {
debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e); debug!(target: "miner", "Hardware wallet has produced invalid signature: {}", e);
errors::account("Invalid signature generated", e) errors::account("Invalid signature generated", e)
}) })
} }

View File

@ -305,8 +305,8 @@ impl Parity for ParityClient {
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>> { fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>> {
let stats = self.light_dispatch.sync.transactions_stats(); let stats = self.light_dispatch.sync.transactions_stats();
Ok(stats.into_iter() Ok(stats.into_iter()
.map(|(hash, stats)| (hash.into(), stats.into())) .map(|(hash, stats)| (hash.into(), stats.into()))
.collect() .collect()
) )
} }

View File

@ -34,7 +34,6 @@ use ethcore::state::StateInfo;
use ethcore_logger::RotatingLogger; use ethcore_logger::RotatingLogger;
use node_health::{NodeHealth, Health}; use node_health::{NodeHealth, Health};
use updater::{Service as UpdateService}; use updater::{Service as UpdateService};
use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::{future, Future};
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
@ -53,7 +52,7 @@ use v1::types::{
use Host; use Host;
/// Parity implementation. /// Parity implementation.
pub struct ParityClient<C, M, U> { pub struct ParityClient<C, M, U> {
client: Arc<C>, client: Arc<C>,
miner: Arc<M>, miner: Arc<M>,
updater: Arc<U>, updater: Arc<U>,
@ -143,11 +142,11 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
.collect() .collect()
) )
} }
fn locked_hardware_accounts_info(&self) -> Result<Vec<String>> { fn locked_hardware_accounts_info(&self) -> Result<Vec<String>> {
self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e)) self.accounts.locked_hardware_accounts().map_err(|e| errors::account("Error communicating with hardware wallet.", e))
} }
fn default_account(&self, meta: Self::Metadata) -> Result<H160> { fn default_account(&self, meta: Self::Metadata) -> Result<H160> {
let dapp_id = meta.dapp_id(); let dapp_id = meta.dapp_id();
@ -312,9 +311,9 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
); );
Ok(ready_transactions Ok(ready_transactions
.into_iter() .into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.collect() .collect()
) )
} }
@ -323,9 +322,9 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
let all_transactions = self.miner.queued_transactions(); let all_transactions = self.miner.queued_transactions();
Ok(all_transactions Ok(all_transactions
.into_iter() .into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition)) .map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.collect() .collect()
) )
} }
@ -336,8 +335,8 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>> { fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>> {
let stats = self.sync.transactions_stats(); let stats = self.sync.transactions_stats();
Ok(stats.into_iter() Ok(stats.into_iter()
.map(|(hash, stats)| (hash.into(), stats.into())) .map(|(hash, stats)| (hash.into(), stats.into()))
.collect() .collect()
) )
} }
@ -345,9 +344,9 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
let transactions = self.miner.local_transactions(); let transactions = self.miner.local_transactions();
let block_number = self.client.chain_info().best_block_number; let block_number = self.client.chain_info().best_block_number;
Ok(transactions Ok(transactions
.into_iter() .into_iter()
.map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition))) .map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition)))
.collect() .collect()
) )
} }

View File

@ -22,7 +22,6 @@ use ethereum_types::Address;
use ethkey::{Brain, Generator, Secret}; use ethkey::{Brain, Generator, Secret};
use ethstore::KeyFile; use ethstore::KeyFile;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use jsonrpc_core::Result; use jsonrpc_core::Result;
use v1::helpers::errors; use v1::helpers::errors;
use v1::traits::ParityAccounts; use v1::traits::ParityAccounts;

View File

@ -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 <admin@parity.io>"]
[dependencies]
ethereum-types = "0.3"
ethkey = { path = "../../ethkey" }

View File

@ -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 <http://www.gnu.org/licenses/>.
//! 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<Address>,
/// Value
pub value: U256,
/// Data
pub data: Vec<u8>,
/// Chain ID
pub chain_id: Option<u64>,
}
pub enum KeyPath {
/// Ethereum.
Ethereum,
/// Ethereum classic.
EthereumClassic,
}
/// `HardwareWalletManager` for devices with no `hardware wallet`
pub struct HardwareWalletManager;
impl HardwareWalletManager {
pub fn new() -> Result<Self, Error> {
Err(Error::NoWallet)
}
pub fn set_key_path(&self, _key_path: KeyPath) {}
pub fn wallet_info(&self, _: &Address) -> Option<WalletInfo> {
None
}
pub fn list_wallets(&self) -> Vec<WalletInfo> {
Vec::with_capacity(0)
}
pub fn list_locked_wallets(&self) -> Result<Vec<String>, Error> {
Err(Error::NoWallet)
}
pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result<bool, Error> {
Err(Error::NoWallet)
}
pub fn sign_transaction(&self, _address: &Address, _transaction: &TransactionInfo, _rlp_transaction: &[u8]) -> Result<Signature, Error> {
Err(Error::NoWallet) }
pub fn sign_message(&self, _address: &Address, _msg: &[u8]) -> Result<Signature, Error> {
Err(Error::NoWallet)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "No hardware wallet!!")
}
}