From 849f5d9a4449ea3631cc49f43f7d8dd04a03831d Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Tue, 1 May 2018 15:01:49 +0200 Subject: [PATCH] Hardware Wallet trait (#8071) * getting started with replacing HardwareWalletManager * trezor and ledger impls the new trait with some drawbacks * Everything move to the new trait * It required lifetime annotations in the trait because [u8] in unsized * Lets now start moving entry point from HardwareWalletManager * rename trait to Wallet * move thread management to the actual wallets * Moved thread management to each respective Wallet * Cleaned up pub items that is needed to be pub * Wallet trait more or less finished * Cleaned up docs * fix tests * omit removed docs * fix spelling, naming och remove old comments * ledger test is broken, add correct logging format * So locally on my machine Linux Ubuntu 17.10 the test doesn't panic but on the CI server libusb::Context::new() fails which I don't understand because it has worked before * Additionally the ledger test is optional so I lean toward ignoring it the CI Server * ignore hardware tests by default * more verbose checking in ledger test --- hw/src/ledger.rs | 393 ++++++++++++++++++++++++++--------------------- hw/src/lib.rs | 132 ++++++++-------- hw/src/trezor.rs | 340 +++++++++++++++++++++------------------- 3 files changed, 469 insertions(+), 396 deletions(-) diff --git a/hw/src/ledger.rs b/hw/src/ledger.rs index e7d616d4f..e31d49f13 100644 --- a/hw/src/ledger.rs +++ b/hw/src/ledger.rs @@ -20,8 +20,11 @@ use std::cmp::min; use std::fmt; use std::str::FromStr; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{H256, Address}; use ethkey::Signature; @@ -29,12 +32,12 @@ use hidapi; use libusb; use parking_lot::{Mutex, RwLock}; -use super::{WalletInfo, KeyPath}; +use super::{WalletInfo, KeyPath, Device, Wallet, USB_DEVICE_CLASS_DEVICE}; /// Ledger vendor ID -pub const LEDGER_VID: u16 = 0x2c97; -/// Legder product IDs: [Nano S and Blue] -pub const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; +const LEDGER_VID: u16 = 0x2c97; +/// Ledger product IDs: [Nano S and Blue] +const LEDGER_PIDS: [u16; 2] = [0x0000, 0x0001]; const ETH_DERIVATION_PATH_BE: [u8; 17] = [4, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/0'/0 const ETC_DERIVATION_PATH_BE: [u8; 21] = [5, 0x80, 0, 0, 44, 0x80, 0, 0, 60, 0x80, 0x02, 0x73, 0xd0, 0x80, 0, 0, 0, 0, 0, 0, 0]; // 44'/60'/160720'/0'/0 @@ -64,8 +67,10 @@ pub enum Error { KeyNotFound, /// Signing has been cancelled by user. UserCancel, - /// Invalid Device + /// Invalid device InvalidDevice, + /// Impossible error + ImpossibleError, } impl fmt::Display for Error { @@ -77,6 +82,7 @@ impl fmt::Display for Error { Error::KeyNotFound => write!(f, "Key not found"), Error::UserCancel => write!(f, "Operation has been cancelled"), Error::InvalidDevice => write!(f, "Unsupported product was entered"), + Error::ImpossibleError => write!(f, "Placeholder error"), } } } @@ -100,157 +106,43 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } + }); - /// Re-populate device list. Only those devices that have Ethereum app open will be added. - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut num_new_devices = 0; - for device in devices { - trace!("Checking device: {:?}", device); - if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { - continue; - } - match self.read_device_info(&usb, &device) { - Ok(info) => { - debug!("Found device: {:?}", info); - if !self.devices.read().iter().any(|d| d.path == info.path) { - num_new_devices += 1; - } - new_devices.push(info); + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); + // Subscribe to all Ledger devices + // This means that we need to check that the given productID is supported + // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to + // More info can be found: + usb_context.register_callback( + Some(LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager)))).expect("usb_callback"); + + // Ledger event handler thread + thread::Builder::new() + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); } - Err(e) => debug!("Error reading device info: {}", e), - }; - } - *self.devices.write() = new_devices; - Ok(num_new_devices) - } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; + } + } + }) + .ok(); - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let mut handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let address = Self::read_wallet_address(&mut handle, *self.key_path.read())?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: address, - }, - }) - } - - fn read_wallet_address(handle: &hidapi::HidDevice, key_path: KeyPath) -> Result { - let ver = Self::send_apdu(handle, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; - if ver.len() != 4 { - return Err(Error::Protocol("Version packet size mismatch")); - } - - let (major, minor, patch) = (ver[1], ver[2], ver[3]); - if major < 1 || (major == 1 && minor == 0 && patch < 3) { - return Err(Error::Protocol("App version 1.0.3 is required.")); - } - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match key_path { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - let key_and_address = Self::send_apdu(handle, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; - if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) - return Err(Error::Protocol("Key packet size mismatch")); - } - let address_string = ::std::str::from_utf8(&key_and_address[67..107]) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - let address = Address::from_str(&address_string) - .map_err(|_| Error::Protocol("Invalid address string"))?; - - Ok(address) - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, data: &[u8]) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - - let eth_path = Ð_DERIVATION_PATH_BE[..]; - let etc_path = &ETC_DERIVATION_PATH_BE[..]; - let derivation_path = match *self.key_path.read() { - KeyPath::Ethereum => eth_path, - KeyPath::EthereumClassic => etc_path, - }; - const MAX_CHUNK_SIZE: usize = 255; - let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; - &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); - let mut dest_offset = derivation_path.len(); - let mut data_pos = 0; - let mut result; - loop { - let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; - let dest_left = MAX_CHUNK_SIZE - dest_offset; - let chunk_data_size = min(dest_left, data.len() - data_pos); - &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&data[data_pos..][0..chunk_data_size]); - result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; - dest_offset = 0; - data_pos += chunk_data_size; - if data_pos == data.len() { - break; - } - } - - if result.len() != 65 { - return Err(Error::Protocol("Signature packet size mismatch")); - } - let v = (result[0] + 1) % 2; - let r = H256::from_slice(&result[1..33]); - let s = H256::from_slice(&result[33..65]); - Ok(Signature::from_rsv(&r, &s, v)) - } - - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } fn send_apdu(handle: &hidapi::HidDevice, command: u8, p1: u8, p2: u8, data: &[u8]) -> Result, Error> { @@ -285,7 +177,7 @@ impl Manager { chunk_index += 1; } - // read response + // Read response chunk_index = 0; let mut message_size = 0; let mut message = Vec::new(); @@ -303,7 +195,7 @@ impl Manager { let mut offset = 5; if seq == 0 { - // read message size and status word. + // Read message size and status word. if chunk_size < 7 { return Err(Error::Protocol("Unexpected chunk header")); } @@ -321,7 +213,7 @@ impl Manager { return Err(Error::Protocol("No status word")); } let status = (message[message.len() - 2] as usize) << 8 | (message[message.len() - 1] as usize); - debug!("Read status {:x}", status); + debug!(target: "hw", "Read status {:x}", status); match status { 0x6700 => Err(Error::Protocol("Incorrect length")), 0x6982 => Err(Error::Protocol("Security status not satisfied (Canceled by user)")), @@ -365,18 +257,166 @@ fn try_connect_polling(ledger: Arc, timeout: Duration) -> bool { false } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a [u8]; + + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + const MAX_CHUNK_SIZE: usize = 255; + let mut chunk: [u8; MAX_CHUNK_SIZE] = [0; MAX_CHUNK_SIZE]; + &mut chunk[0..derivation_path.len()].copy_from_slice(derivation_path); + let mut dest_offset = derivation_path.len(); + let mut data_pos = 0; + let mut result; + loop { + let p1 = if data_pos == 0 { 0x00 } else { 0x80 }; + let dest_left = MAX_CHUNK_SIZE - dest_offset; + let chunk_data_size = min(dest_left, transaction.len() - data_pos); + &mut chunk[dest_offset..][0..chunk_data_size].copy_from_slice(&transaction[data_pos..][0..chunk_data_size]); + result = Self::send_apdu(&handle, commands::SIGN_ETH_TRANSACTION, p1, 0, &chunk[0..(dest_offset + chunk_data_size)])?; + dest_offset = 0; + data_pos += chunk_data_size; + if data_pos == transaction.len() { + break; + } + } + + if result.len() != 65 { + return Err(Error::Protocol("Signature packet size mismatch")); + } + let v = (result[0] + 1) % 2; + let r = H256::from_slice(&result[1..33]); + let s = H256::from_slice(&result[33..65]); + Ok(Signature::from_rsv(&r, &s, v)) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut num_new_devices = 0; + for device in devices { + trace!("Checking device: {:?}", device); + if device.vendor_id != LEDGER_VID || !LEDGER_PIDS.contains(&device.product_id) { + continue; + } + match self.read_device(&usb, &device) { + Ok(info) => { + debug!(target: "hw", "Found device: {:?}", info); + if !self.devices.read().iter().any(|d| d.path == info.path) { + num_new_devices += 1; + } + new_devices.push(info); + + } + Err(e) => debug!(target: "hw", "Error reading device info: {}", e), + }; + } + *self.devices.write() = new_devices; + Ok(num_new_devices) + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + // This variant is not possible, but the trait forces this return type + Ok(None) => Err(Error::ImpossibleError), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + // Not used because it is not supported by Ledger + fn list_locked_devices(&self) -> Vec { + vec![] + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error> { + let ver = Self::send_apdu(device, commands::GET_APP_CONFIGURATION, 0, 0, &[])?; + if ver.len() != 4 { + return Err(Error::Protocol("Version packet size mismatch")); + } + + let (major, minor, patch) = (ver[1], ver[2], ver[3]); + if major < 1 || (major == 1 && minor == 0 && patch < 3) { + return Err(Error::Protocol("App version 1.0.3 is required.")); + } + + let eth_path = Ð_DERIVATION_PATH_BE[..]; + let etc_path = &ETC_DERIVATION_PATH_BE[..]; + let derivation_path = match *self.key_path.read() { + KeyPath::Ethereum => eth_path, + KeyPath::EthereumClassic => etc_path, + }; + let key_and_address = Self::send_apdu(device, commands::GET_ETH_PUBLIC_ADDRESS, 0, 0, derivation_path)?; + if key_and_address.len() != 107 { // 1 + 65 PK + 1 + 40 Addr (ascii-hex) + return Err(Error::Protocol("Key packet size mismatch")); + } + let address_string = ::std::str::from_utf8(&key_and_address[67..107]) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + let address = Address::from_str(&address_string) + .map_err(|_| Error::Protocol("Invalid address string"))?; + + Ok(Some(address)) + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + /// Ledger event handler -/// A seperate thread is hanedling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { ledger: Weak, } impl EventHandler { /// Ledger event handler constructor - pub fn new(ledger: Weak) -> Self { + fn new(ledger: Weak) -> Self { Self { ledger: ledger } } } @@ -402,27 +442,34 @@ impl libusb::Hotplug for EventHandler { } #[test] +#[ignore] +/// This test can't be run without an actual ledger device connected fn smoke() { use rustc_hex::FromHex; - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); - manager.update_devices().unwrap(); - for d in &*manager.devices.read() { - println!("Device: {:?}", d); - } + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().expect("HidApi"))); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).expect("Ledger Manager"); - if let Some(address) = manager.list_devices().first().map(|d| d.address.clone()) { - let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); - let signature = manager.sign_transaction(&address, &tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); - let signature = manager.sign_transaction(&address, &large_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); - let signature = manager.sign_transaction(&address, &huge_tx); - println!("Got {:?}", signature); - assert!(signature.is_ok()); - } + // Update device list + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); + + // Fetch the ethereum address of a connected ledger device + let address = manager.list_devices() + .iter() + .filter(|d| d.manufacturer == "Ledger".to_string()) + .nth(0) + .map(|d| d.address.clone()) + .expect("No ledger device detected"); + + let tx = FromHex::from_hex("eb018504a817c80082520894a6ca2e6707f2cc189794a9dd459d5b05ed1bcd1c8703f26fcfb7a22480018080").unwrap(); + let signature = manager.sign_transaction(&address, &tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let large_tx = FromHex::from_hex("f8cb81968504e3b2920083024f279475b02a3c39710d6a3f2870d0d788299d48e790f180b8a4b61d27f6000000000000000000000000e1af840a5a1cb1efdf608a97aa632f4aa39ed199000000000000000000000000000000000000000000000000105ff43f46a9a800000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018080").unwrap(); + let signature = manager.sign_transaction(&address, &large_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); + let huge_tx = FromHex::from_hex("f935e98201048505d21dba00833b82608080b935946103e86003908155620d2f00600455601460055560a060405260608190527f2e2e2e00000000000000000000000000000000000000000000000000000000006080908152600d805460008290527f2e2e2e00000000000000000000000000000000000000000000000000000000068255909260008051602062003474833981519152602060026001851615610100026000190190941693909304601f0192909204820192909190620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b5b50620001009291505b80821115620000fc5760008155600101620000e6565b5090565b5050600e8054600360ff199182168117909255604080518082019091528281527f2e2e2e00000000000000000000000000000000000000000000000000000000006020918201908152600f80546000829052825160069516949094178155937f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac80260026101006001871615026000190190951694909404601f019290920483019290620001d7565b82800160010185558215620001d7579182015b82811115620001d7578251825591602001919060010190620001ba565b5b50620001fb9291505b80821115620000fc5760008155600101620000e6565b5090565b50506010805460ff19166001179055346200000057604051620034943803806200349483398101604090815281516020830151918301516060840151919390810191015b5b5b60068054600160a060020a0319166c01000000000000000000000000338102041790558151600d80546000829052909160008051602062003474833981519152602060026101006001861615026000190190941693909304601f908101849004820193870190839010620002c157805160ff1916838001178555620002f1565b82800160010185558215620002f1579182015b82811115620002f1578251825591602001919060010190620002d4565b5b50620003159291505b80821115620000fc5760008155600101620000e6565b5090565b505080600f9080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200036557805160ff191683800117855562000395565b8280016001018555821562000395579182015b828111156200039557825182559160200191906001019062000378565b5b50620003b99291505b80821115620000fc5760008155600101620000e6565b5090565b5050600980546c01000000000000000000000000808602819004600160a060020a0319928316179092556007805487840293909304929091169190911790555b505050505b613066806200040e6000396000f300606060405236156102035760e060020a600035046306fdde03811461034b578063095ea7b3146103c65780630b0b6d5b146103ed5780631b1ccc47146103fc57806320e870931461047757806323b872dd1461049657806325b29d84146104c057806327187991146104df578063277ccde2146104f15780632e1fbfcd14610510578063308b2fdc14610532578063313ce5671461055457806338cc48311461057757806340eddc4e146105a057806341f4793a146105bf578063467ed261146105de578063471ad963146105fd5780634e860ebb1461060f5780634efbe9331461061e57806354786b4e1461064257806354e35ba2146106bd57806358793ad4146106d25780635abedab21461073f5780635af2f8211461074e57806360483a3f1461076d57806360d12fa0146107da578063698f2e84146108035780636a749986146108155780636d5f66391461082a5780636e9c36831461083c57806370a082311461085e5780637a290fe5146108805780637e7541461461088f57806394c41bdb1461090a57806395d89b4114610929578063962a64cd146109a4578063a0b6533214610a09578063a9059cbb14610a2b578063ab62438f14610a52578063b63ca98114610aa9578063b7c54c6f14610abb578063c4e41b2214610ada578063ca7c4dba14610af9578063cb79e31b14610b18578063dd62ed3e14610b3a575b6103495b60006000600c546000141561021b57610000565b600354600c54670de0b6b3a764000091349091020204915060009050816001600030600160a060020a031681526020019081526020016000205410156102c557600160a060020a033016600090815260016020526040902054600c54909250828115610000570466038d7ea4c68000023403905033600160a060020a03166108fc829081150290604051809050600060405180830381858888f1935050505015156102c557610000565b5b600160a060020a03338116600081815260016020908152604080832080548801905530909416825283822080548790039055601380543487900301908190559154600c548551908152918201879052845190949293927f5a0391f2a67f11ed0034b68f8cf14e7e41d6f86e0a7622f2af5ea8f07b488396928290030190a45b5050565b005b3461000057610358610b5f565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103d9600435602435610bed565b604080519115158252519081900360200190f35b3461000057610349610c58565b005b3461000057610358610dbc565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484610e5a565b60408051918252519081900360200190f35b34610000576103d9600435602435604435610ef9565b604080519115158252519081900360200190f35b3461000057610484610ff3565b60408051918252519081900360200190f35b3461000057610349600435611002565b005b346100005761048461105a565b60408051918252519081900360200190f35b3461000057610484600435611061565b60408051918252519081900360200190f35b346100005761048460043561108d565b60408051918252519081900360200190f35b34610000576105616110b9565b6040805160ff9092168252519081900360200190f35b34610000576105846110c2565b60408051600160a060020a039092168252519081900360200190f35b34610000576104846110c7565b60408051918252519081900360200190f35b34610000576104846110ce565b60408051918252519081900360200190f35b34610000576104846110d5565b60408051918252519081900360200190f35b3461000057610349600435611174565b005b34610000576103496113b5565b005b34610000576103d9600435611407565b604080519115158252519081900360200190f35b3461000057610358611549565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576103496004356024356115e7565b005b346100005760408051602060046024803582810135601f8101859004850286018501909652858552610726958335959394604494939290920191819084018382808284375094965061167e95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610349611c13565b005b3461000057610484611d46565b60408051918252519081900360200190f35b346100005760408051602060046024803582810135601f81018590048502860185019096528585526107269583359593946044949392909201918190840183828082843750949650611d4d95505050505050565b6040805192835290151560208301528051918290030190f35b3461000057610584612303565b60408051600160a060020a039092168252519081900360200190f35b3461000057610349600435612313565b005b3461000057610349600435602435612347565b005b346100005761034960043561252f565b005b3461000057610484600435612941565b60408051918252519081900360200190f35b346100005761048460043561298d565b60408051918252519081900360200190f35b34610000576103496129ac565b005b3461000057610358612a13565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484612ab1565b60408051918252519081900360200190f35b3461000057610358612ab8565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103b85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3461000057610484600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650612b4695505050505050565b60408051918252519081900360200190f35b3461000057610484600435612b63565b60408051918252519081900360200190f35b34610000576103d9600435602435612b8c565b604080519115158252519081900360200190f35b3461000057610349600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496505093359350612c3c92505050565b005b3461000057610349600435612f38565b005b3461000057610484612f90565b60408051918252519081900360200190f35b346100005761048461300c565b60408051918252519081900360200190f35b3461000057610484613013565b60408051918252519081900360200190f35b346100005761048460043561301a565b60408051918252519081900360200190f35b3461000057610484600435602435613039565b60408051918252519081900360200190f35b600d805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b601a54600090600160a060020a03161515610c7257610000565b600160a060020a0333166000908152600a60205260409020541515610c9657610000565b600160a060020a0333166000908152601d602052604090205460ff1615610cbc57610000565b601b54426212750090910111610cd157610000565b600160a060020a0333166000818152601d60209081526040808320805460ff19166001179055600a8252918290208054601c805490910190555482519384529083015280517f475c7605c08471fdc551a58d2c318b163628c5852f69323a1b91c34eb0bb09339281900390910190a150601154601c54606490910490604682029010610db857601a5460068054600160a060020a031916606060020a600160a060020a0393841681020417908190556040805191909216815290517f6b8184e23a898262087be50aa3ea5de648451e63f94413e810586c25282d58c2916020908290030190a15b5b50565b604080516020808201835260008252600d8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b600f805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600160a060020a038316600090815260016020526040812054829010801590610f495750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b8015610f555750600082115b15610fe757600160a060020a03808516600081815260016020908152604080832080548890039055878516808452818420805489019055848452600283528184203390961684529482529182902080548790039055815186815291517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610feb56610feb565b5060005b5b9392505050565b600160a060020a033016315b90565b60065433600160a060020a0390811691161461101d57610000565b600c8190556040805182815290517f0bbd501ef336990995d82b5e3fd82a15abe1ff10c982757a1698ac5d1c3e79579181900360200190a15b5b50565b600b545b90565b6000601882815481101561000057906000526020600020906007020160005b506004015490505b919050565b6000601882815481101561000057906000526020600020906007020160005b506001015490505b919050565b600e5460ff1681565b305b90565b6013545b90565b601c545b90565b600d805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152600093610ef39391929091830182828015610ee95780601f10610ebe57610100808354040283529160200191610ee9565b820191906000526020600020905b815481529060010190602001808311610ecc57829003601f168201915b5050505050612b46565b90505b90565b600654600090819033600160a060020a0390811691161461119457610000565b60008381526014602052604090205415156111ae57610000565b60008381526014602052604090206005015433600160a060020a039081169116146111d857610000565b60008381526014602052604090206005015460a060020a900460ff16156111fe57610000565b601154600084815260146020526040902060040154606490910460370292508290111561122a57610000565b60008381526014602052604081206005015460a860020a900460ff16600181116100005714156112eb57600954600084815260146020908152604080832060058101546001909101548251840185905282517fa9059cbb000000000000000000000000000000000000000000000000000000008152600160a060020a0392831660048201526024810191909152915194169363a9059cbb93604480840194938390030190829087803b156100005760325a03f1156100005750611389915050565b60008381526014602052604080822060058101546001909101549151600160a060020a039091169282156108fc02929190818181858888f160008881526014602090815260409182902060058101546001909101548351600160a060020a0390921682529181019190915281519297507f2648a7e2f9c34700b91370233666e5118fa8be3e0c21fed4f7402b941df8efdd9650829003019350915050a15b6000838152601460205260409020600501805460a060020a60ff02191660a060020a1790555b5b505050565b60065433600160a060020a039081169116146113d057610000565b6010805460ff191690556040517fb48c7f694f0a3b9b22d7e61c60ff8aebbb107314b6b698fc489ff3f017cb57e090600090a15b5b565b600060006000600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f115610000575050604051514210905061147c57610000565b60085433600160a060020a0390811691161461149757610000565b5050600b54600160a060020a03328181166000908152600a6020526040902080549386029384019055601180548401905560128054860190556008549092916114e39130911683610ef9565b506114ee8282612b8c565b50600054601154600b5460408051918252602082018590528051600160a060020a038716927fb4d6befef2def3d17bcb13c2b882ec4fa047f33157446d3e0e6094b2a21609ac92908290030190a4600192505b5b5050919050565b604080516020808201835260008252600f8054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b60065433600160a060020a0390811691161461160257610000565b60105460ff16151561161357610000565b600160a060020a0330166000908152600160209081526040808320805485019055600c859055825484019283905580518481529051839286927f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c3929081900390910190a45b5b5b5050565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a039081169116146116ed57610000565b60115460649004935060056016541115801561170c5750836005540288115b1561171657610000565b61171e612f90565b8811156117305761172d612f90565b97505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016000815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061182057805160ff191683800117855561184d565b8280016001018555821561184d579182015b8281111561184d578251825591602001919060010190611832565b5b5061186e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116119c9576007028160070283600052602060002091820191016119c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10611968575061199a565b601f01602090049060005260206000209081019061199a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701611925565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a4a57805160ff1916838001178555611a77565b82800160010185558215611a77579182015b82811115611a77578251825591602001919060010190611a5c565b5b50611a989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a90810204021790555050505060166000815460010191905081905550426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b60065460009033600160a060020a03908116911614611c3157610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f1156100005750506040515162dd7c00014210159050611ca657610000565b604051600160a060020a0333811691309091163180156108fc02916000818181858888f1600954909550600160a060020a0316935063a9059cbb9250339150611cef9050612f90565b6000604051602001526040518360e060020a0281526004018083600160a060020a0316815260200182815260200192505050602060405180830381600087803b156100005760325a03f115610000575050505b5b50565b6016545b90565b6040805161010081018252600080825260208083018290528351908101845281815292820192909252606081018290526080810182905260a0810182905260c0810182905260e08101829052600654829182918291829133600160a060020a03908116911614611dbc57610000565b60105460ff1615611dcc57610000565b6000611dd73061298d565b1115611de257610000565b6017546212750001421015611df657610000565b6013546064900493508360055402881115611e1057610000565b30600160a060020a031631881115611e305730600160a060020a03163197505b60003642604051808484808284378201915050828152602001935050505060405180910390209250600454420191506101006040519081016040528084815260200189815260200188815260200183815260200160008152602001338152602001600081526020016001815260200150905080601460008560001916815260200190815260200160002060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f2057805160ff1916838001178555611f4d565b82800160010185558215611f4d579182015b82811115611f4d578251825591602001919060010190611f32565b5b50611f6e9291505b8082111561186a5760008155600101611856565b5090565b5050606082015160038201556080820151600482015560a08201516005909101805460c084015160e09094015160f860020a90810281900460a860020a0260a860020a60ff02199582029190910460a060020a0260a060020a60ff0219606060020a95860295909504600160a060020a031990931692909217939093161792909216179055601880546001810180835582818380158290116120c9576007028160070283600052602060002091820191016120c991905b8082111561186a5760006000820160009055600182016000905560028201805460018160011615610100020316600290046000825580601f10612068575061209a565b601f01602090049060005260206000209081019061209a91905b8082111561186a5760008155600101611856565b5090565b5b50506000600382018190556004820155600581018054600160b060020a0319169055600701612025565b5090565b5b505050916000526020600020906007020160005b83909190915060008201518160000155602082015181600101556040820151816002019080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061214a57805160ff1916838001178555612177565b82800160010185558215612177579182015b8281111561217757825182559160200191906001019061215c565b5b506121989291505b8082111561186a5760008155600101611856565b5090565b5050606082015181600301556080820151816004015560a08201518160050160006101000a815481600160a060020a030219169083606060020a90810204021790555060c08201518160050160146101000a81548160ff021916908360f860020a90810204021790555060e08201518160050160156101000a81548160ff021916908360f860020a908102040217905550505050426017819055507f1a1eea7d2a0f099c2f19efb4e101fcf220558c9f4fbc6961b33fbe02d3a7be908389848a3360405180866000191681526020018581526020018481526020018060200183600160a060020a031681526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015611bee5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a1826001955095505b5b505050509250929050565b600654600160a060020a03165b90565b600854600160a060020a03161561232957610000565b60088054600160a060020a031916606060020a838102041790555b50565b60065433600160a060020a0390811691161461236257610000565b60105460ff16151561237357610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421090506123e257610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663cdd933326000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151421015905061245257610000565b600854600160a060020a0316151561246957610000565b6000805482018155600160a060020a03308116808352600160209081526040808520805487019055600b8790556002825280852060088054861687529083529481902080548701905593548451868152945193169391927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3600054601154600b546040805185815290517f10cb430288a1696de11938bc5362c6f8c60e58808237bce4436b93a8573e00c39181900360200190a45b5b5b5b5b5050565b604080516101008082018352600080835260208084018290528451808201865282815284860152606084018290526080840182905260a0840182905260c0840182905260e0840182905285825260148152848220855180850187528154815260018083015482850152600280840180548a51600019948216159099029390930190921604601f8101859004850287018501895280875296979496879692959394938601938301828280156126245780601f106125f957610100808354040283529160200191612624565b820191906000526020600020905b81548152906001019060200180831161260757829003601f168201915b505050918352505060038201546020820152600482015460408201526005820154600160a060020a038116606083015260ff60a060020a820481161515608084015260a09092019160a860020a909104166001811161000057905250600085815260146020526040902054909350151561269d57610000565b60008481526014602052604090206005015460a060020a900460ff16156126c357610000565b60008481526014602052604090206003015442106126e057610000565b6000848152601460209081526040808320600160a060020a033316845260060190915290205460ff161561271357610000565b600160a060020a0333166000818152600a6020908152604080832054888452601483528184206004810180548301905594845260069094019091529020805460ff19166001179055915061276684612941565b6000858152601460205260409020601880549293509091839081101561000057906000526020600020906007020160005b50600082015481600001556001820154816001015560028201816002019080546001816001161561010002031660029004828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612801578054855561283d565b8280016001018555821561283d57600052602060002091601f016020900482015b8281111561283d578254825591600101919060010190612822565b5b5061285e9291505b8082111561186a5760008155600101611856565b5090565b5050600382810154908201556004808301549082015560059182018054929091018054600160a060020a031916606060020a600160a060020a0394851681020417808255825460a060020a60ff021990911660f860020a60a060020a9283900460ff908116820282900490930291909117808455935460a860020a60ff021990941660a860020a9485900490921681020490920291909117905560408051868152339092166020830152818101849052517f8f8bbb8c1937f844f6a094cd4c6eeab8ed5e36f83952e6306ffb2c11fffe5bce916060908290030190a15b50505050565b6000805b60185481101561298657601881815481101561000057906000526020600020906007020160005b505483141561297d57809150612986565b5b600101612945565b5b50919050565b600160a060020a0381166000908152600160205260409020545b919050565b60065433600160a060020a039081169116146129c757610000565b600160a060020a03301660009081526001602052604080822080548354038355829055517fe0987873419fe09d3c9a3e0267f4daf163e812d512f867abaf6bf9822f141a8b9190a15b5b565b60408051602080820183526000825260198054845160026001831615610100026000190190921691909104601f810184900484028201840190955284815292939091830182828015610e4f5780601f10610e2457610100808354040283529160200191610e4f565b820191906000526020600020905b815481529060010190602001808311610e3257829003601f168201915b505050505090505b90565b6011545b90565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610be55780601f10610bba57610100808354040283529160200191610be5565b820191906000526020600020905b815481529060010190602001808311610bc857829003601f168201915b505050505081565b6000602082511115612b5757610000565b5060208101515b919050565b6000601882815481101561000057906000526020600020906007020160005b505490505b919050565b600160a060020a033316600090815260016020526040812054829010801590612bb55750600082115b15612c2d57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610c5256610c52565b506000610c52565b5b92915050565b600160a060020a0333166000908152600a60205260409020541515612c6057610000565b600760009054906101000a9004600160a060020a0316600160a060020a031663d4884b566000604051602001526040518160e060020a028152600401809050602060405180830381600087803b156100005760325a03f11561000057505060405151626ebe00014210159050612cd557610000565b601b5415801590612cef5750426019600201546212750001115b15612cf957610000565b6040805160808101825283815260208082018490524262127500018284015233600160a060020a03166000908152600a8252928320546060830152815180516019805495819052939484937f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969560026001841615610100026000190190931692909204601f90810182900483019490910190839010612da257805160ff1916838001178555612dcf565b82800160010185558215612dcf579182015b82811115612dcf578251825591602001919060010190612db4565b5b50612df09291505b8082111561186a5760008155600101611856565b5090565b505060208201518160010160006101000a815481600160a060020a030219169083606060020a908102040217905550604082015181600201556060820151816003015590505060016019600401600033600160a060020a0316815260200190815260200160002060006101000a81548160ff021916908360f860020a9081020402179055507f854a9cc4d907d23cd8dcc72af48dc0e6a87e6f76376a309a0ffa3231ce8e13363383426212750001846040518085600160a060020a031681526020018060200184815260200183600160a060020a031681526020018281038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015612f235780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a15b5050565b60065433600160a060020a03908116911614612f5357610000565b600b819055600080546011546040519192909184917f17a7f53ef43da32c3936b4ac2b060caff5c4b03cd24b1c8e96a191eb1ec48d1591a45b5b50565b6000600960009054906101000a9004600160a060020a0316600160a060020a03166370a08231306000604051602001526040518260e060020a0281526004018082600160a060020a03168152602001915050602060405180830381600087803b156100005760325a03f115610000575050604051519150505b90565b6000545b90565b600c545b90565b600160a060020a0381166000908152600a60205260409020545b919050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b9291505056d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb500000000000000000000000069381683bde924cef65f1c97f7c8fb769a20409300000000000000000000000014f37b574242d366558db61f3335289a5035c506000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000018546573742074657374657220746573746573742063616d700000000000000000000000000000000000000000000000000000000000000000000000000000000354455300000000000000000000000000000000000000000000000000000000001ba033230fce515bea9de982fe85e0ec8fe892984bc3070ad633daab20eb370864d5a05deb41870e2117197b84cb71110fc0508fa7457165cb8cb82cb8d4d801e6e3f1").unwrap(); + let signature = manager.sign_transaction(&address, &huge_tx); + println!("Got {:?}", signature); + assert!(signature.is_ok()); } diff --git a/hw/src/lib.rs b/hw/src/lib.rs index 9bfec8341..f51be356a 100644 --- a/hw/src/lib.rs +++ b/hw/src/lib.rs @@ -16,7 +16,8 @@ //! Hardware wallet management. -#![warn(missing_docs)] +#[warn(missing_docs)] +#[warn(warnings)] extern crate ethereum_types; extern crate ethkey; @@ -38,12 +39,60 @@ use std::fmt; use std::sync::Arc; use std::sync::atomic; use std::sync::atomic::AtomicBool; -use std::thread; -use std::time::Duration; use ethereum_types::U256; const USB_DEVICE_CLASS_DEVICE: u8 = 0; +#[derive(Debug)] +pub struct Device { + path: String, + info: WalletInfo, +} + +pub trait Wallet<'a> { + /// Error + type Error; + /// Transaction data format + type Transaction; + + /// Sign transaction data with wallet managing `address`. + fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result; + + /// Set key derivation path for a chain. + fn set_key_path(&self, key_path: KeyPath); + + /// Re-populate device list + /// Note, this assumes all devices are iterated over and updated + fn update_devices(&self) -> Result; + + /// Read device info + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result; + + /// List connected and acknowledged wallets + fn list_devices(&self) -> Vec; + + /// List locked wallets + /// This may be moved if it is the wrong assumption, for example this is not supported by Ledger + /// Then this method return a empty vector + fn list_locked_devices(&self) -> Vec; + + /// Get wallet info. + fn get_wallet(&self, address: &Address) -> Option; + + /// Generate ethereum address for a Wallet + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Self::Error>; + + /// Open a device using `device path` + /// Note, f - is a closure that borrows HidResult + /// HidDevice is in turn a type alias for a `c_void function pointer` + /// For further information see: + /// * + /// * + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result; +} + + /// Hardware wallet error. #[derive(Debug)] pub enum Error { @@ -144,70 +193,13 @@ pub struct HardwareWalletManager { trezor: Arc, } - impl HardwareWalletManager { /// Hardware wallet constructor pub fn new() -> Result { - let usb_context_trezor = Arc::new(libusb::Context::new()?); - let usb_context_ledger = Arc::new(libusb::Context::new()?); - let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); - let ledger = Arc::new(ledger::Manager::new(hidapi.clone())); - let trezor = Arc::new(trezor::Manager::new(hidapi.clone())); - - // Subscribe to TREZOR V1 - // Note, this support only TREZOR V1 becasue TREZOR V2 has another vendorID for some reason - // Also, we now only support one product as the second argument specifies - usb_context_trezor.register_callback( - Some(trezor::TREZOR_VID), Some(trezor::TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), - Box::new(trezor::EventHandler::new(Arc::downgrade(&trezor))))?; - - // Subscribe to all Ledger Devices - // This means that we need to check that the given productID is supported - // None => LIBUSB_HOTPLUG_MATCH_ANY, in other words that all are subscribed to - // More info can be found: http://libusb.sourceforge.net/api-1.0/group__hotplug.html#gae6c5f1add6cc754005549c7259dc35ea - usb_context_ledger.register_callback( - Some(ledger::LEDGER_VID), None, Some(USB_DEVICE_CLASS_DEVICE), - Box::new(ledger::EventHandler::new(Arc::downgrade(&ledger))))?; - let exiting = Arc::new(AtomicBool::new(false)); - let thread_exiting_ledger = exiting.clone(); - let thread_exiting_trezor = exiting.clone(); - let l = ledger.clone(); - let t = trezor.clone(); - - // Ledger event thread - thread::Builder::new() - .name("hw_wallet_ledger".to_string()) - .spawn(move || { - if let Err(e) = l.update_devices() { - debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e); - } - loop { - usb_context_ledger.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Ledger event handler error: {}", e)); - if thread_exiting_ledger.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); - - // Trezor event thread - thread::Builder::new() - .name("hw_wallet_trezor".to_string()) - .spawn(move || { - if let Err(e) = t.update_devices() { - debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); - } - loop { - usb_context_trezor.handle_events(Some(Duration::from_millis(500))) - .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); - if thread_exiting_trezor.load(atomic::Ordering::Acquire) { - break; - } - } - }) - .ok(); + let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?)); + let ledger = ledger::Manager::new(hidapi.clone(), exiting.clone())?; + let trezor = trezor::Manager::new(hidapi.clone(), exiting.clone())?; Ok(HardwareWalletManager { exiting: exiting, @@ -217,6 +209,8 @@ impl HardwareWalletManager { } /// Select key derivation path for a chain. + /// Currently, only one hard-coded keypath is supported + /// It is managed by `ethcore/account_provider` pub fn set_key_path(&self, key_path: KeyPath) { self.ledger.set_key_path(key_path); self.trezor.set_key_path(key_path); @@ -231,24 +225,26 @@ impl HardwareWalletManager { } /// Return a list of paths to locked hardware wallets + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn list_locked_wallets(&self) -> Result, Error> { Ok(self.trezor.list_locked_devices()) } /// Get connected wallet info. pub fn wallet_info(&self, address: &Address) -> Option { - if let Some(info) = self.ledger.device_info(address) { + if let Some(info) = self.ledger.get_wallet(address) { Some(info) } else { - self.trezor.device_info(address) + self.trezor.get_wallet(address) } } /// Sign transaction data with wallet managing `address`. pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo, encoded_transaction: &[u8]) -> Result { - if self.ledger.device_info(address).is_some() { + if self.ledger.get_wallet(address).is_some() { Ok(self.ledger.sign_transaction(address, encoded_transaction)?) - } else if self.trezor.device_info(address).is_some() { + } else if self.trezor.get_wallet(address).is_some() { Ok(self.trezor.sign_transaction(address, t_info)?) } else { Err(Error::KeyNotFound) @@ -256,6 +252,8 @@ impl HardwareWalletManager { } /// Send a pin to a device at a certain path to unlock it + /// This is only applicable to Trezor because Ledger only appears as + /// a device when it is unlocked pub fn pin_matrix_ack(&self, path: &str, pin: &str) -> Result { self.trezor.pin_matrix_ack(path, pin).map_err(Error::TrezorDevice) } diff --git a/hw/src/trezor.rs b/hw/src/trezor.rs index 7db226718..044e5487b 100644 --- a/hw/src/trezor.rs +++ b/hw/src/trezor.rs @@ -19,12 +19,15 @@ //! and https://github.com/trezor/trezor-common/blob/master/protob/protocol.md //! for protocol details. -use super::{WalletInfo, TransactionInfo, KeyPath}; +use super::{WalletInfo, TransactionInfo, KeyPath, Wallet, Device, USB_DEVICE_CLASS_DEVICE}; use std::cmp::{min, max}; use std::fmt; use std::sync::{Arc, Weak}; +use std::sync::atomic; +use std::sync::atomic::AtomicBool; use std::time::{Duration, Instant}; +use std::thread; use ethereum_types::{U256, H256, Address}; use ethkey::Signature; @@ -37,9 +40,9 @@ use protobuf::{Message, ProtobufEnum}; use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck}; /// Trezor v1 vendor ID -pub const TREZOR_VID: u16 = 0x534c; +const TREZOR_VID: u16 = 0x534c; /// Trezor product IDs -pub const TREZOR_PIDS: [u16; 1] = [0x0001]; +const TREZOR_PIDS: [u16; 1] = [0x0001]; const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0 const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0 @@ -94,12 +97,6 @@ pub struct Manager { key_path: RwLock, } -#[derive(Debug)] -struct Device { - path: String, - info: WalletInfo, -} - /// HID Version used for the Trezor device enum HidVersion { V1, @@ -108,102 +105,42 @@ enum HidVersion { impl Manager { /// Create a new instance. - pub fn new(hidapi: Arc>) -> Manager { - Manager { + pub fn new(hidapi: Arc>, exiting: Arc) -> Result, libusb::Error> { + let manager = Arc::new(Manager { usb: hidapi, devices: RwLock::new(Vec::new()), locked_devices: RwLock::new(Vec::new()), key_path: RwLock::new(KeyPath::Ethereum), - } - } + }); - /// Re-populate device list - pub fn update_devices(&self) -> Result { - let mut usb = self.usb.lock(); - usb.refresh_devices(); - let devices = usb.devices(); - let mut new_devices = Vec::new(); - let mut locked_devices = Vec::new(); - let mut error = None; - for usb_device in devices { - let is_trezor = usb_device.vendor_id == TREZOR_VID; - let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); - let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; + let usb_context = Arc::new(libusb::Context::new()?); + let m = manager.clone(); - trace!( - "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", - usb_device, - is_trezor, - is_supported_product, - is_valid, - ); - if !is_trezor || !is_supported_product || !is_valid { - continue; - } - match self.read_device_info(&usb, &usb_device) { - Ok(device) => new_devices.push(device), - Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), - Err(e) => { - warn!("Error reading device: {:?}", e); - error = Some(e); + // Subscribe to TREZOR V1 + // Note, this support only TREZOR V1 because TREZOR V2 has a different vendorID for some reason + // Also, we now only support one product as the second argument specifies + usb_context.register_callback( + Some(TREZOR_VID), Some(TREZOR_PIDS[0]), Some(USB_DEVICE_CLASS_DEVICE), + Box::new(EventHandler::new(Arc::downgrade(&manager))))?; + + // Trezor event thread + thread::Builder::new() + .name("hw_wallet_trezor".to_string()) + .spawn(move || { + if let Err(e) = m.update_devices() { + debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e); } - } - } - let count = new_devices.len(); - trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); - *self.devices.write() = new_devices; - *self.locked_devices.write() = locked_devices; - match error { - Some(e) => Err(e), - None => Ok(count), - } - } + loop { + usb_context.handle_events(Some(Duration::from_millis(500))) + .unwrap_or_else(|e| debug!(target: "hw", "Trezor event handler error: {}", e)); + if exiting.load(atomic::Ordering::Acquire) { + break; + } + } + }) + .ok(); - fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { - let handle = self.open_path(|| usb.open_path(&dev_info.path))?; - let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); - let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); - let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); - match self.get_address(&handle) { - Ok(Some(addr)) => { - Ok(Device { - path: dev_info.path.clone(), - info: WalletInfo { - name: name, - manufacturer: manufacturer, - serial: serial, - address: addr, - }, - }) - } - Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), - Err(e) => Err(e), - } - } - - /// Select key derivation path for a known chain. - pub fn set_key_path(&self, key_path: KeyPath) { - *self.key_path.write() = key_path; - } - - /// List connected wallets. This only returns wallets that are ready to be used. - pub fn list_devices(&self) -> Vec { - self.devices.read().iter().map(|d| d.info.clone()).collect() - } - - pub fn list_locked_devices(&self) -> Vec { - (*self.locked_devices.read()).clone() - } - - /// Get wallet info. - pub fn device_info(&self, address: &Address) -> Option { - self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) - } - - fn open_path(&self, f: F) -> Result - where F: Fn() -> Result - { - f().map_err(Into::into) + Ok(manager) } pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result { @@ -227,61 +164,6 @@ impl Manager { unlocked } - fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { - let typ = MessageType::MessageType_EthereumGetAddress; - let mut message = EthereumGetAddress::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_show_display(false); - self.send_device_message(&device, &typ, &message)?; - - let (resp_type, bytes) = self.read_device_response(&device)?; - match resp_type { - MessageType::MessageType_EthereumAddress => { - let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; - Ok(Some(From::from(response.get_address()))) - } - _ => Ok(None), - } - } - - /// Sign transaction data with wallet managing `address`. - pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo) -> Result { - let usb = self.usb.lock(); - let devices = self.devices.read(); - let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; - let handle = self.open_path(|| usb.open_path(&device.path))?; - let msg_type = MessageType::MessageType_EthereumSignTx; - let mut message = EthereumSignTx::new(); - match *self.key_path.read() { - KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), - KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), - } - message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); - message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); - message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); - message.set_value(self.u256_to_be_vec(&t_info.value)); - - match t_info.to { - Some(addr) => { - message.set_to(addr.to_vec()) - } - None => (), - } - let first_chunk_length = min(t_info.data.len(), 1024); - let chunk = &t_info.data[0..first_chunk_length]; - message.set_data_initial_chunk(chunk.to_vec()); - message.set_data_length(t_info.data.len() as u32); - if let Some(c_id) = t_info.chain_id { - message.set_chain_id(c_id as u32); - } - - self.send_device_message(&handle, &msg_type, &message)?; - - self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) - } fn u256_to_be_vec(&self, val: &U256) -> Vec { let mut buf = [0u8; 32]; @@ -400,6 +282,152 @@ impl Manager { } } +impl <'a>Wallet<'a> for Manager { + type Error = Error; + type Transaction = &'a TransactionInfo; + + fn sign_transaction(&self, address: &Address, t_info: Self::Transaction) -> + Result { + let usb = self.usb.lock(); + let devices = self.devices.read(); + let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?; + let handle = self.open_path(|| usb.open_path(&device.path))?; + let msg_type = MessageType::MessageType_EthereumSignTx; + let mut message = EthereumSignTx::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_nonce(self.u256_to_be_vec(&t_info.nonce)); + message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit)); + message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price)); + message.set_value(self.u256_to_be_vec(&t_info.value)); + + match t_info.to { + Some(addr) => { + message.set_to(addr.to_vec()) + } + None => (), + } + let first_chunk_length = min(t_info.data.len(), 1024); + let chunk = &t_info.data[0..first_chunk_length]; + message.set_data_initial_chunk(chunk.to_vec()); + message.set_data_length(t_info.data.len() as u32); + if let Some(c_id) = t_info.chain_id { + message.set_chain_id(c_id as u32); + } + + self.send_device_message(&handle, &msg_type, &message)?; + + self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..]) + } + + fn set_key_path(&self, key_path: KeyPath) { + *self.key_path.write() = key_path; + } + + fn update_devices(&self) -> Result { + let mut usb = self.usb.lock(); + usb.refresh_devices(); + let devices = usb.devices(); + let mut new_devices = Vec::new(); + let mut locked_devices = Vec::new(); + let mut error = None; + for usb_device in devices { + let is_trezor = usb_device.vendor_id == TREZOR_VID; + let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id); + let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0; + + trace!( + "Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}", + usb_device, + is_trezor, + is_supported_product, + is_valid, + ); + if !is_trezor || !is_supported_product || !is_valid { + continue; + } + match self.read_device(&usb, &usb_device) { + Ok(device) => new_devices.push(device), + Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()), + Err(e) => { + warn!("Error reading device: {:?}", e); + error = Some(e); + } + } + } + let count = new_devices.len(); + trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices); + *self.devices.write() = new_devices; + *self.locked_devices.write() = locked_devices; + match error { + Some(e) => Err(e), + None => Ok(count), + } + } + + fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result { + let handle = self.open_path(|| usb.open_path(&dev_info.path))?; + let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned()); + let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned()); + let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned()); + match self.get_address(&handle) { + Ok(Some(addr)) => { + Ok(Device { + path: dev_info.path.clone(), + info: WalletInfo { + name: name, + manufacturer: manufacturer, + serial: serial, + address: addr, + }, + }) + } + Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())), + Err(e) => Err(e), + } + } + + fn list_devices(&self) -> Vec { + self.devices.read().iter().map(|d| d.info.clone()).collect() + } + + fn list_locked_devices(&self) -> Vec { + (*self.locked_devices.read()).clone() + } + + fn get_wallet(&self, address: &Address) -> Option { + self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone()) + } + + fn get_address(&self, device: &hidapi::HidDevice) -> Result, Error> { + let typ = MessageType::MessageType_EthereumGetAddress; + let mut message = EthereumGetAddress::new(); + match *self.key_path.read() { + KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()), + KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()), + } + message.set_show_display(false); + self.send_device_message(&device, &typ, &message)?; + + let (resp_type, bytes) = self.read_device_response(&device)?; + match resp_type { + MessageType::MessageType_EthereumAddress => { + let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?; + Ok(Some(From::from(response.get_address()))) + } + _ => Ok(None), + } + } + + fn open_path(&self, f: F) -> Result + where F: Fn() -> Result + { + f().map_err(Into::into) + } +} + // Try to connect to the device using polling in at most the time specified by the `timeout` fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { let start_time = Instant::now(); @@ -412,11 +440,11 @@ fn try_connect_polling(trezor: Arc, duration: Duration) -> bool { } /// Trezor event handler -/// A separate thread is handeling incoming events +/// A separate thread is handling incoming events /// /// Note, that this run to completion and race-conditions can't occur but this can /// therefore starve other events for being process with a spinlock or similar -pub struct EventHandler { +struct EventHandler { trezor: Weak, } @@ -455,10 +483,10 @@ fn test_signature() { use ethereum_types::{H160, H256, U256}; let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap())); - let manager = Manager::new(hidapi.clone()); + let manager = Manager::new(hidapi.clone(), Arc::new(AtomicBool::new(false))).unwrap(); let addr: Address = H160::from("some_addr"); - manager.update_devices().unwrap(); + assert_eq!(try_connect_polling(manager.clone(), Duration::from_millis(500)), true); let t_info = TransactionInfo { nonce: U256::from(1),