github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/accounts/usbwallet/ledger_wallet.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // This file contains the implementation for interacting with the Ledger hardware
    18  // wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
    19  // https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
    20  
    21  // +build !ios
    22  
    23  package usbwallet
    24  
    25  import (
    26  	"encoding/binary"
    27  	"encoding/hex"
    28  	"errors"
    29  	"fmt"
    30  	"io"
    31  	"math/big"
    32  	"sync"
    33  	"time"
    34  
    35  	ethereum "github.com/atheioschain/go-atheios"
    36  	"github.com/atheioschain/go-atheios/accounts"
    37  	"github.com/atheioschain/go-atheios/common"
    38  	"github.com/atheioschain/go-atheios/core/types"
    39  	"github.com/atheioschain/go-atheios/logger"
    40  	"github.com/atheioschain/go-atheios/logger/glog"
    41  	"github.com/atheioschain/go-atheios/rlp"
    42  	"github.com/karalabe/gousb/usb"
    43  	"golang.org/x/net/context"
    44  )
    45  
    46  // Maximum time between wallet health checks to detect USB unplugs.
    47  const ledgerHeartbeatCycle = time.Second
    48  
    49  // Minimum time to wait between self derivation attempts, even it the user is
    50  // requesting accounts like crazy.
    51  const ledgerSelfDeriveThrottling = time.Second
    52  
    53  // ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
    54  type ledgerOpcode byte
    55  
    56  // ledgerParam1 is an enumeration encoding the supported Ledger parameters for
    57  // specific opcodes. The same parameter values may be reused between opcodes.
    58  type ledgerParam1 byte
    59  
    60  // ledgerParam2 is an enumeration encoding the supported Ledger parameters for
    61  // specific opcodes. The same parameter values may be reused between opcodes.
    62  type ledgerParam2 byte
    63  
    64  const (
    65  	ledgerOpRetrieveAddress  ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path
    66  	ledgerOpSignTransaction  ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters
    67  	ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
    68  
    69  	ledgerP1DirectlyFetchAddress    ledgerParam1 = 0x00 // Return address directly from the wallet
    70  	ledgerP1ConfirmFetchAddress     ledgerParam1 = 0x01 // Require a user confirmation before returning the address
    71  	ledgerP1InitTransactionData     ledgerParam1 = 0x00 // First transaction data block for signing
    72  	ledgerP1ContTransactionData     ledgerParam1 = 0x80 // Subsequent transaction data block for signing
    73  	ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
    74  	ledgerP2ReturnAddressChainCode  ledgerParam2 = 0x01 // Require a user confirmation before returning the address
    75  )
    76  
    77  // errReplyInvalidHeader is the error message returned by a Ledfer data exchange
    78  // if the device replies with a mismatching header. This usually means the device
    79  // is in browser mode.
    80  var errReplyInvalidHeader = errors.New("invalid reply header")
    81  
    82  // ledgerWallet represents a live USB Ledger hardware wallet.
    83  type ledgerWallet struct {
    84  	context    *usb.Context  // USB context to interface libusb through
    85  	hardwareID deviceID      // USB identifiers to identify this device type
    86  	locationID uint16        // USB bus and address to identify this device instance
    87  	url        *accounts.URL // Textual URL uniquely identifying this wallet
    88  
    89  	device  *usb.Device  // USB device advertising itself as a Ledger wallet
    90  	input   usb.Endpoint // Input endpoint to send data to this device
    91  	output  usb.Endpoint // Output endpoint to receive data from this device
    92  	failure error        // Any failure that would make the device unusable
    93  
    94  	version  [3]byte                                    // Current version of the Ledger Ethereum app (zero if app is offline)
    95  	browser  bool                                       // Flag whether the Ledger is in browser mode (reply channel mismatch)
    96  	accounts []accounts.Account                         // List of derive accounts pinned on the Ledger
    97  	paths    map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
    98  
    99  	deriveNextPath accounts.DerivationPath   // Next derivation path for account auto-discovery
   100  	deriveNextAddr common.Address            // Next derived account address for auto-discovery
   101  	deriveChain    ethereum.ChainStateReader // Blockchain state reader to discover used account with
   102  	deriveReq      chan chan struct{}        // Channel to request a self-derivation on
   103  	deriveQuit     chan chan error           // Channel to terminate the self-deriver with
   104  
   105  	healthQuit chan chan error
   106  
   107  	// Locking a hardware wallet is a bit special. Since hardware devices are lower
   108  	// performing, any communication with them might take a non negligible amount of
   109  	// time. Worse still, waiting for user confirmation can take arbitrarily long,
   110  	// but exclusive communication must be upheld during. Locking the entire wallet
   111  	// in the mean time however would stall any parts of the system that don't want
   112  	// to communicate, just read some state (e.g. list the accounts).
   113  	//
   114  	// As such, a hardware wallet needs two locks to function correctly. A state
   115  	// lock can be used to protect the wallet's software-side internal state, which
   116  	// must not be held exlusively during hardware communication. A communication
   117  	// lock can be used to achieve exclusive access to the device itself, this one
   118  	// however should allow "skipping" waiting for operations that might want to
   119  	// use the device, but can live without too (e.g. account self-derivation).
   120  	//
   121  	// Since we have two locks, it's important to know how to properly use them:
   122  	//   - Communication requires the `device` to not change, so obtaining the
   123  	//     commsLock should be done after having a stateLock.
   124  	//   - Communication must not disable read access to the wallet state, so it
   125  	//     must only ever hold a *read* lock to stateLock.
   126  	commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked
   127  	stateLock sync.RWMutex  // Protects read and write access to the wallet struct fields
   128  }
   129  
   130  // URL implements accounts.Wallet, returning the URL of the Ledger device.
   131  func (w *ledgerWallet) URL() accounts.URL {
   132  	return *w.url // Immutable, no need for a lock
   133  }
   134  
   135  // Status implements accounts.Wallet, always whether the Ledger is opened, closed
   136  // or whether the Ethereum app was not started on it.
   137  func (w *ledgerWallet) Status() string {
   138  	w.stateLock.RLock() // No device communication, state lock is enough
   139  	defer w.stateLock.RUnlock()
   140  
   141  	if w.failure != nil {
   142  		return fmt.Sprintf("Failed: %v", w.failure)
   143  	}
   144  	if w.device == nil {
   145  		return "Closed"
   146  	}
   147  	if w.browser {
   148  		return "Ethereum app in browser mode"
   149  	}
   150  	if w.offline() {
   151  		return "Ethereum app offline"
   152  	}
   153  	return fmt.Sprintf("Ethereum app v%d.%d.%d online", w.version[0], w.version[1], w.version[2])
   154  }
   155  
   156  // offline returns whether the wallet and the Ethereum app is offline or not.
   157  //
   158  // The method assumes that the state lock is held!
   159  func (w *ledgerWallet) offline() bool {
   160  	return w.version == [3]byte{0, 0, 0}
   161  }
   162  
   163  // failed returns if the USB device wrapped by the wallet failed for some reason.
   164  // This is used by the device scanner to report failed wallets as departed.
   165  //
   166  // The method assumes that the state lock is *not* held!
   167  func (w *ledgerWallet) failed() bool {
   168  	w.stateLock.RLock() // No device communication, state lock is enough
   169  	defer w.stateLock.RUnlock()
   170  
   171  	return w.failure != nil
   172  }
   173  
   174  // Open implements accounts.Wallet, attempting to open a USB connection to the
   175  // Ledger hardware wallet. The Ledger does not require a user passphrase, so that
   176  // parameter is silently discarded.
   177  func (w *ledgerWallet) Open(passphrase string) error {
   178  	w.stateLock.Lock() // State lock is enough since there's no connection yet at this point
   179  	defer w.stateLock.Unlock()
   180  
   181  	// If the wallet was already opened, don't try to open again
   182  	if w.device != nil {
   183  		return accounts.ErrWalletAlreadyOpen
   184  	}
   185  	// Otherwise iterate over all USB devices and find this again (no way to directly do this)
   186  	// Iterate over all attached devices and fetch those seemingly Ledger
   187  	devices, err := w.context.ListDevices(func(desc *usb.Descriptor) bool {
   188  		// Only open this single specific device
   189  		return desc.Vendor == w.hardwareID.Vendor && desc.Product == w.hardwareID.Product &&
   190  			uint16(desc.Bus)<<8+uint16(desc.Address) == w.locationID
   191  	})
   192  	if err != nil {
   193  		return err
   194  	}
   195  	if len(devices) == 0 {
   196  		return accounts.ErrUnknownWallet
   197  	}
   198  	// Device opened, attach to the input and output endpoints
   199  	device := devices[0]
   200  
   201  	var invalid string
   202  	switch {
   203  	case len(device.Descriptor.Configs) == 0:
   204  		invalid = "no endpoint config available"
   205  	case len(device.Descriptor.Configs[0].Interfaces) == 0:
   206  		invalid = "no endpoint interface available"
   207  	case len(device.Descriptor.Configs[0].Interfaces[0].Setups) == 0:
   208  		invalid = "no endpoint setup available"
   209  	case len(device.Descriptor.Configs[0].Interfaces[0].Setups[0].Endpoints) < 2:
   210  		invalid = "not enough IO endpoints available"
   211  	}
   212  	if invalid != "" {
   213  		device.Close()
   214  		return fmt.Errorf("ledger wallet [%s] invalid: %s", w.url, invalid)
   215  	}
   216  	// Open the input and output endpoints to the device
   217  	input, err := device.OpenEndpoint(
   218  		device.Descriptor.Configs[0].Config,
   219  		device.Descriptor.Configs[0].Interfaces[0].Number,
   220  		device.Descriptor.Configs[0].Interfaces[0].Setups[0].Number,
   221  		device.Descriptor.Configs[0].Interfaces[0].Setups[0].Endpoints[1].Address,
   222  	)
   223  	if err != nil {
   224  		device.Close()
   225  		return fmt.Errorf("ledger wallet [%s] input open failed: %v", w.url, err)
   226  	}
   227  	output, err := device.OpenEndpoint(
   228  		device.Descriptor.Configs[0].Config,
   229  		device.Descriptor.Configs[0].Interfaces[0].Number,
   230  		device.Descriptor.Configs[0].Interfaces[0].Setups[0].Number,
   231  		device.Descriptor.Configs[0].Interfaces[0].Setups[0].Endpoints[0].Address,
   232  	)
   233  	if err != nil {
   234  		device.Close()
   235  		return fmt.Errorf("ledger wallet [%s] output open failed: %v", w.url, err)
   236  	}
   237  	// Wallet seems to be successfully opened, guess if the Ethereum app is running
   238  	w.device, w.input, w.output = device, input, output
   239  	w.commsLock = make(chan struct{}, 1)
   240  	w.commsLock <- struct{}{} // Enable lock
   241  
   242  	w.paths = make(map[common.Address]accounts.DerivationPath)
   243  
   244  	w.deriveReq = make(chan chan struct{})
   245  	w.deriveQuit = make(chan chan error)
   246  	w.healthQuit = make(chan chan error)
   247  
   248  	defer func() {
   249  		go w.heartbeat()
   250  		go w.selfDerive()
   251  	}()
   252  
   253  	if _, err = w.ledgerDerive(accounts.DefaultBaseDerivationPath); err != nil {
   254  		// Ethereum app is not running or in browser mode, nothing more to do, return
   255  		if err == errReplyInvalidHeader {
   256  			w.browser = true
   257  		}
   258  		return nil
   259  	}
   260  	// Try to resolve the Ethereum app's version, will fail prior to v1.0.2
   261  	if w.version, err = w.ledgerVersion(); err != nil {
   262  		w.version = [3]byte{1, 0, 0} // Assume worst case, can't verify if v1.0.0 or v1.0.1
   263  	}
   264  	return nil
   265  }
   266  
   267  // heartbeat is a health check loop for the Ledger wallets to periodically verify
   268  // whether they are still present or if they malfunctioned. It is needed because:
   269  //  - libusb on Windows doesn't support hotplug, so we can't detect USB unplugs
   270  //  - communication timeout on the Ledger requires a device power cycle to fix
   271  func (w *ledgerWallet) heartbeat() {
   272  	glog.V(logger.Debug).Infof("%s health-check started", w.url.String())
   273  	defer glog.V(logger.Debug).Infof("%s health-check stopped", w.url.String())
   274  
   275  	// Execute heartbeat checks until termination or error
   276  	var (
   277  		errc chan error
   278  		err  error
   279  	)
   280  	for errc == nil && err == nil {
   281  		// Wait until termination is requested or the heartbeat cycle arrives
   282  		select {
   283  		case errc = <-w.healthQuit:
   284  			// Termination requested
   285  			continue
   286  		case <-time.After(ledgerHeartbeatCycle):
   287  			// Heartbeat time
   288  		}
   289  		// Execute a tiny data exchange to see responsiveness
   290  		w.stateLock.RLock()
   291  		if w.device == nil {
   292  			// Terminated while waiting for the lock
   293  			w.stateLock.RUnlock()
   294  			continue
   295  		}
   296  		<-w.commsLock // Don't lock state while resolving version
   297  		_, err = w.ledgerVersion()
   298  		w.commsLock <- struct{}{}
   299  		w.stateLock.RUnlock()
   300  
   301  		if err == usb.ERROR_IO || err == usb.ERROR_NO_DEVICE {
   302  			w.stateLock.Lock() // Lock state to tear the wallet down
   303  			w.failure = err
   304  			w.close()
   305  			w.stateLock.Unlock()
   306  		}
   307  		// Ignore uninteresting errors
   308  		err = nil
   309  	}
   310  	// In case of error, wait for termination
   311  	if err != nil {
   312  		glog.V(logger.Debug).Infof("%s health-check failed: %v", w.url.String(), err)
   313  		errc = <-w.healthQuit
   314  	}
   315  	errc <- err
   316  }
   317  
   318  // Close implements accounts.Wallet, closing the USB connection to the Ledger.
   319  func (w *ledgerWallet) Close() error {
   320  	// Ensure the wallet was opened
   321  	w.stateLock.RLock()
   322  	hQuit, dQuit := w.healthQuit, w.deriveQuit
   323  	w.stateLock.RUnlock()
   324  
   325  	// Terminate the health checks
   326  	var herr error
   327  	if hQuit != nil {
   328  		errc := make(chan error)
   329  		hQuit <- errc
   330  		herr = <-errc // Save for later, we *must* close the USB
   331  	}
   332  	// Terminate the self-derivations
   333  	var derr error
   334  	if dQuit != nil {
   335  		errc := make(chan error)
   336  		dQuit <- errc
   337  		derr = <-errc // Save for later, we *must* close the USB
   338  	}
   339  	// Terminate the device connection
   340  	w.stateLock.Lock()
   341  	defer w.stateLock.Unlock()
   342  
   343  	w.healthQuit = nil
   344  	w.deriveQuit = nil
   345  	w.deriveReq = nil
   346  
   347  	if err := w.close(); err != nil {
   348  		return err
   349  	}
   350  	if herr != nil {
   351  		return herr
   352  	}
   353  	return derr
   354  }
   355  
   356  // close is the internal wallet closer that terminates the USB connection and
   357  // resets all the fields to their defaults.
   358  //
   359  // Note, close assumes the state lock is held!
   360  func (w *ledgerWallet) close() error {
   361  	// Allow duplicate closes, especially for health-check failures
   362  	if w.device == nil {
   363  		return nil
   364  	}
   365  	// Close the device, clear everything, then return
   366  	err := w.device.Close()
   367  
   368  	w.device, w.input, w.output = nil, nil, nil
   369  	w.browser, w.version = false, [3]byte{}
   370  	w.accounts, w.paths = nil, nil
   371  
   372  	return err
   373  }
   374  
   375  // Accounts implements accounts.Wallet, returning the list of accounts pinned to
   376  // the Ledger hardware wallet. If self-derivation was enabled, the account list
   377  // is periodically expanded based on current chain state.
   378  func (w *ledgerWallet) Accounts() []accounts.Account {
   379  	// Attempt self-derivation if it's running
   380  	reqc := make(chan struct{}, 1)
   381  	select {
   382  	case w.deriveReq <- reqc:
   383  		// Self-derivation request accepted, wait for it
   384  		<-reqc
   385  	default:
   386  		// Self-derivation offline, throttled or busy, skip
   387  	}
   388  	// Return whatever account list we ended up with
   389  	w.stateLock.RLock()
   390  	defer w.stateLock.RUnlock()
   391  
   392  	cpy := make([]accounts.Account, len(w.accounts))
   393  	copy(cpy, w.accounts)
   394  	return cpy
   395  }
   396  
   397  // selfDerive is an account derivation loop that upon request attempts to find
   398  // new non-zero accounts.
   399  func (w *ledgerWallet) selfDerive() {
   400  	glog.V(logger.Debug).Infof("%s self-derivation started", w.url.String())
   401  	defer glog.V(logger.Debug).Infof("%s self-derivation stopped", w.url.String())
   402  
   403  	// Execute self-derivations until termination or error
   404  	var (
   405  		reqc chan struct{}
   406  		errc chan error
   407  		err  error
   408  	)
   409  	for errc == nil && err == nil {
   410  		// Wait until either derivation or termination is requested
   411  		select {
   412  		case errc = <-w.deriveQuit:
   413  			// Termination requested
   414  			continue
   415  		case reqc = <-w.deriveReq:
   416  			// Account discovery requested
   417  		}
   418  		// Derivation needs a chain and device access, skip if either unavailable
   419  		w.stateLock.RLock()
   420  		if w.device == nil || w.deriveChain == nil || w.offline() {
   421  			w.stateLock.RUnlock()
   422  			reqc <- struct{}{}
   423  			continue
   424  		}
   425  		select {
   426  		case <-w.commsLock:
   427  		default:
   428  			w.stateLock.RUnlock()
   429  			reqc <- struct{}{}
   430  			continue
   431  		}
   432  		// Device lock obtained, derive the next batch of accounts
   433  		var (
   434  			accs  []accounts.Account
   435  			paths []accounts.DerivationPath
   436  
   437  			nextAddr = w.deriveNextAddr
   438  			nextPath = w.deriveNextPath
   439  
   440  			context = context.Background()
   441  		)
   442  		for empty := false; !empty; {
   443  			// Retrieve the next derived Ethereum account
   444  			if nextAddr == (common.Address{}) {
   445  				if nextAddr, err = w.ledgerDerive(nextPath); err != nil {
   446  					glog.V(logger.Warn).Infof("%s self-derivation failed: %v", w.url.String(), err)
   447  					break
   448  				}
   449  			}
   450  			// Check the account's status against the current chain state
   451  			var (
   452  				balance *big.Int
   453  				nonce   uint64
   454  			)
   455  			balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
   456  			if err != nil {
   457  				glog.V(logger.Warn).Infof("%s self-derivation balance retrieval failed: %v", w.url.String(), err)
   458  				break
   459  			}
   460  			nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
   461  			if err != nil {
   462  				glog.V(logger.Warn).Infof("%s self-derivation nonce retrieval failed: %v", w.url.String(), err)
   463  				break
   464  			}
   465  			// If the next account is empty, stop self-derivation, but add it nonetheless
   466  			if balance.BitLen() == 0 && nonce == 0 {
   467  				empty = true
   468  			}
   469  			// We've just self-derived a new account, start tracking it locally
   470  			path := make(accounts.DerivationPath, len(nextPath))
   471  			copy(path[:], nextPath[:])
   472  			paths = append(paths, path)
   473  
   474  			account := accounts.Account{
   475  				Address: nextAddr,
   476  				URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   477  			}
   478  			accs = append(accs, account)
   479  
   480  			// Display a log message to the user for new (or previously empty accounts)
   481  			if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
   482  				glog.V(logger.Info).Infof("%s discovered %s (balance %22v, nonce %4d) at %s", w.url.String(), nextAddr.Hex(), balance, nonce, path)
   483  			}
   484  			// Fetch the next potential account
   485  			if !empty {
   486  				nextAddr = common.Address{}
   487  				nextPath[len(nextPath)-1]++
   488  			}
   489  		}
   490  		// Self derivation complete, release device lock
   491  		w.commsLock <- struct{}{}
   492  		w.stateLock.RUnlock()
   493  
   494  		// Insert any accounts successfully derived
   495  		w.stateLock.Lock()
   496  		for i := 0; i < len(accs); i++ {
   497  			if _, ok := w.paths[accs[i].Address]; !ok {
   498  				w.accounts = append(w.accounts, accs[i])
   499  				w.paths[accs[i].Address] = paths[i]
   500  			}
   501  		}
   502  		// Shift the self-derivation forward
   503  		// TODO(karalabe): don't overwrite changes from wallet.SelfDerive
   504  		w.deriveNextAddr = nextAddr
   505  		w.deriveNextPath = nextPath
   506  		w.stateLock.Unlock()
   507  
   508  		// Notify the user of termination and loop after a bit of time (to avoid trashing)
   509  		reqc <- struct{}{}
   510  		if err == nil {
   511  			select {
   512  			case errc = <-w.deriveQuit:
   513  				// Termination requested, abort
   514  			case <-time.After(ledgerSelfDeriveThrottling):
   515  				// Waited enough, willing to self-derive again
   516  			}
   517  		}
   518  	}
   519  	// In case of error, wait for termination
   520  	if err != nil {
   521  		glog.V(logger.Debug).Infof("%s self-derivation failed: %s", w.url.String(), err)
   522  		errc = <-w.deriveQuit
   523  	}
   524  	errc <- err
   525  }
   526  
   527  // Contains implements accounts.Wallet, returning whether a particular account is
   528  // or is not pinned into this Ledger instance. Although we could attempt to resolve
   529  // unpinned accounts, that would be an non-negligible hardware operation.
   530  func (w *ledgerWallet) Contains(account accounts.Account) bool {
   531  	w.stateLock.RLock()
   532  	defer w.stateLock.RUnlock()
   533  
   534  	_, exists := w.paths[account.Address]
   535  	return exists
   536  }
   537  
   538  // Derive implements accounts.Wallet, deriving a new account at the specific
   539  // derivation path. If pin is set to true, the account will be added to the list
   540  // of tracked accounts.
   541  func (w *ledgerWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
   542  	// Try to derive the actual account and update its URL if successful
   543  	w.stateLock.RLock() // Avoid device disappearing during derivation
   544  
   545  	if w.device == nil || w.offline() {
   546  		w.stateLock.RUnlock()
   547  		return accounts.Account{}, accounts.ErrWalletClosed
   548  	}
   549  	<-w.commsLock // Avoid concurrent hardware access
   550  	address, err := w.ledgerDerive(path)
   551  	w.commsLock <- struct{}{}
   552  
   553  	w.stateLock.RUnlock()
   554  
   555  	// If an error occurred or no pinning was requested, return
   556  	if err != nil {
   557  		return accounts.Account{}, err
   558  	}
   559  	account := accounts.Account{
   560  		Address: address,
   561  		URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   562  	}
   563  	if !pin {
   564  		return account, nil
   565  	}
   566  	// Pinning needs to modify the state
   567  	w.stateLock.Lock()
   568  	defer w.stateLock.Unlock()
   569  
   570  	if _, ok := w.paths[address]; !ok {
   571  		w.accounts = append(w.accounts, account)
   572  		w.paths[address] = path
   573  	}
   574  	return account, nil
   575  }
   576  
   577  // SelfDerive implements accounts.Wallet, trying to discover accounts that the
   578  // user used previously (based on the chain state), but ones that he/she did not
   579  // explicitly pin to the wallet manually. To avoid chain head monitoring, self
   580  // derivation only runs during account listing (and even then throttled).
   581  func (w *ledgerWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {
   582  	w.stateLock.Lock()
   583  	defer w.stateLock.Unlock()
   584  
   585  	w.deriveNextPath = make(accounts.DerivationPath, len(base))
   586  	copy(w.deriveNextPath[:], base[:])
   587  
   588  	w.deriveNextAddr = common.Address{}
   589  	w.deriveChain = chain
   590  }
   591  
   592  // SignHash implements accounts.Wallet, however signing arbitrary data is not
   593  // supported for Ledger wallets, so this method will always return an error.
   594  func (w *ledgerWallet) SignHash(acc accounts.Account, hash []byte) ([]byte, error) {
   595  	return nil, accounts.ErrNotSupported
   596  }
   597  
   598  // SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
   599  // wallet to request a confirmation from the user. It returns either the signed
   600  // transaction or a failure if the user denied the transaction.
   601  //
   602  // Note, if the version of the Ethereum application running on the Ledger wallet is
   603  // too old to sign EIP-155 transactions, but such is requested nonetheless, an error
   604  // will be returned opposed to silently signing in Homestead mode.
   605  func (w *ledgerWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   606  	w.stateLock.RLock() // Comms have own mutex, this is for the state fields
   607  	defer w.stateLock.RUnlock()
   608  
   609  	// If the wallet is closed, or the Ethereum app doesn't run, abort
   610  	if w.device == nil || w.offline() {
   611  		return nil, accounts.ErrWalletClosed
   612  	}
   613  	// Make sure the requested account is contained within
   614  	path, ok := w.paths[account.Address]
   615  	if !ok {
   616  		return nil, accounts.ErrUnknownAccount
   617  	}
   618  	// Ensure the wallet is capable of signing the given transaction
   619  	if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
   620  		return nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
   621  	}
   622  	// All infos gathered and metadata checks out, request signing
   623  	<-w.commsLock
   624  	defer func() { w.commsLock <- struct{}{} }()
   625  
   626  	return w.ledgerSign(path, account.Address, tx, chainID)
   627  }
   628  
   629  // SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary
   630  // data is not supported for Ledger wallets, so this method will always return
   631  // an error.
   632  func (w *ledgerWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
   633  	return nil, accounts.ErrNotSupported
   634  }
   635  
   636  // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
   637  // transaction with the given account using passphrase as extra authentication.
   638  // Since the Ledger does not support extra passphrases, it is silently ignored.
   639  func (w *ledgerWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   640  	return w.SignTx(account, tx, chainID)
   641  }
   642  
   643  // ledgerVersion retrieves the current version of the Ethereum wallet app running
   644  // on the Ledger wallet.
   645  //
   646  // The version retrieval protocol is defined as follows:
   647  //
   648  //   CLA | INS | P1 | P2 | Lc | Le
   649  //   ----+-----+----+----+----+---
   650  //    E0 | 06  | 00 | 00 | 00 | 04
   651  //
   652  // With no input data, and the output data being:
   653  //
   654  //   Description                                        | Length
   655  //   ---------------------------------------------------+--------
   656  //   Flags 01: arbitrary data signature enabled by user | 1 byte
   657  //   Application major version                          | 1 byte
   658  //   Application minor version                          | 1 byte
   659  //   Application patch version                          | 1 byte
   660  func (w *ledgerWallet) ledgerVersion() ([3]byte, error) {
   661  	// Send the request and wait for the response
   662  	reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil)
   663  	if err != nil {
   664  		return [3]byte{}, err
   665  	}
   666  	if len(reply) != 4 {
   667  		return [3]byte{}, errors.New("reply not of correct size")
   668  	}
   669  	// Cache the version for future reference
   670  	var version [3]byte
   671  	copy(version[:], reply[1:])
   672  	return version, nil
   673  }
   674  
   675  // ledgerDerive retrieves the currently active Ethereum address from a Ledger
   676  // wallet at the specified derivation path.
   677  //
   678  // The address derivation protocol is defined as follows:
   679  //
   680  //   CLA | INS | P1 | P2 | Lc  | Le
   681  //   ----+-----+----+----+-----+---
   682  //    E0 | 02  | 00 return address
   683  //               01 display address and confirm before returning
   684  //                  | 00: do not return the chain code
   685  //                  | 01: return the chain code
   686  //                       | var | 00
   687  //
   688  // Where the input data is:
   689  //
   690  //   Description                                      | Length
   691  //   -------------------------------------------------+--------
   692  //   Number of BIP 32 derivations to perform (max 10) | 1 byte
   693  //   First derivation index (big endian)              | 4 bytes
   694  //   ...                                              | 4 bytes
   695  //   Last derivation index (big endian)               | 4 bytes
   696  //
   697  // And the output data is:
   698  //
   699  //   Description             | Length
   700  //   ------------------------+-------------------
   701  //   Public Key length       | 1 byte
   702  //   Uncompressed Public Key | arbitrary
   703  //   Ethereum address length | 1 byte
   704  //   Ethereum address        | 40 bytes hex ascii
   705  //   Chain code if requested | 32 bytes
   706  func (w *ledgerWallet) ledgerDerive(derivationPath []uint32) (common.Address, error) {
   707  	// Flatten the derivation path into the Ledger request
   708  	path := make([]byte, 1+4*len(derivationPath))
   709  	path[0] = byte(len(derivationPath))
   710  	for i, component := range derivationPath {
   711  		binary.BigEndian.PutUint32(path[1+4*i:], component)
   712  	}
   713  	// Send the request and wait for the response
   714  	reply, err := w.ledgerExchange(ledgerOpRetrieveAddress, ledgerP1DirectlyFetchAddress, ledgerP2DiscardAddressChainCode, path)
   715  	if err != nil {
   716  		return common.Address{}, err
   717  	}
   718  	// Discard the public key, we don't need that for now
   719  	if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
   720  		return common.Address{}, errors.New("reply lacks public key entry")
   721  	}
   722  	reply = reply[1+int(reply[0]):]
   723  
   724  	// Extract the Ethereum hex address string
   725  	if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
   726  		return common.Address{}, errors.New("reply lacks address entry")
   727  	}
   728  	hexstr := reply[1 : 1+int(reply[0])]
   729  
   730  	// Decode the hex sting into an Ethereum address and return
   731  	var address common.Address
   732  	hex.Decode(address[:], hexstr)
   733  	return address, nil
   734  }
   735  
   736  // ledgerSign sends the transaction to the Ledger wallet, and waits for the user
   737  // to confirm or deny the transaction.
   738  //
   739  // The transaction signing protocol is defined as follows:
   740  //
   741  //   CLA | INS | P1 | P2 | Lc  | Le
   742  //   ----+-----+----+----+-----+---
   743  //    E0 | 04  | 00: first transaction data block
   744  //               80: subsequent transaction data block
   745  //                  | 00 | variable | variable
   746  //
   747  // Where the input for the first transaction block (first 255 bytes) is:
   748  //
   749  //   Description                                      | Length
   750  //   -------------------------------------------------+----------
   751  //   Number of BIP 32 derivations to perform (max 10) | 1 byte
   752  //   First derivation index (big endian)              | 4 bytes
   753  //   ...                                              | 4 bytes
   754  //   Last derivation index (big endian)               | 4 bytes
   755  //   RLP transaction chunk                            | arbitrary
   756  //
   757  // And the input for subsequent transaction blocks (first 255 bytes) are:
   758  //
   759  //   Description           | Length
   760  //   ----------------------+----------
   761  //   RLP transaction chunk | arbitrary
   762  //
   763  // And the output data is:
   764  //
   765  //   Description | Length
   766  //   ------------+---------
   767  //   signature V | 1 byte
   768  //   signature R | 32 bytes
   769  //   signature S | 32 bytes
   770  func (w *ledgerWallet) ledgerSign(derivationPath []uint32, address common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   771  	// We need to modify the timeouts to account for user feedback
   772  	defer func(old time.Duration) { w.device.ReadTimeout = old }(w.device.ReadTimeout)
   773  	w.device.ReadTimeout = time.Hour * 24 * 30 // Timeout requires a Ledger power cycle, only if you must
   774  
   775  	// Flatten the derivation path into the Ledger request
   776  	path := make([]byte, 1+4*len(derivationPath))
   777  	path[0] = byte(len(derivationPath))
   778  	for i, component := range derivationPath {
   779  		binary.BigEndian.PutUint32(path[1+4*i:], component)
   780  	}
   781  	// Create the transaction RLP based on whether legacy or EIP155 signing was requeste
   782  	var (
   783  		txrlp []byte
   784  		err   error
   785  	)
   786  	if chainID == nil {
   787  		if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data()}); err != nil {
   788  			return nil, err
   789  		}
   790  	} else {
   791  		if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil {
   792  			return nil, err
   793  		}
   794  	}
   795  	payload := append(path, txrlp...)
   796  
   797  	// Send the request and wait for the response
   798  	var (
   799  		op    = ledgerP1InitTransactionData
   800  		reply []byte
   801  	)
   802  	for len(payload) > 0 {
   803  		// Calculate the size of the next data chunk
   804  		chunk := 255
   805  		if chunk > len(payload) {
   806  			chunk = len(payload)
   807  		}
   808  		// Send the chunk over, ensuring it's processed correctly
   809  		reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk])
   810  		if err != nil {
   811  			return nil, err
   812  		}
   813  		// Shift the payload and ensure subsequent chunks are marked as such
   814  		payload = payload[chunk:]
   815  		op = ledgerP1ContTransactionData
   816  	}
   817  	// Extract the Ethereum signature and do a sanity validation
   818  	if len(reply) != 65 {
   819  		return nil, errors.New("reply lacks signature")
   820  	}
   821  	signature := append(reply[1:], reply[0])
   822  
   823  	// Create the correct signer and signature transform based on the chain ID
   824  	var signer types.Signer
   825  	if chainID == nil {
   826  		signer = new(types.HomesteadSigner)
   827  	} else {
   828  		signer = types.NewEIP155Signer(chainID)
   829  		signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
   830  	}
   831  	// Inject the final signature into the transaction and sanity check the sender
   832  	signed, err := tx.WithSignature(signer, signature)
   833  	if err != nil {
   834  		return nil, err
   835  	}
   836  	sender, err := types.Sender(signer, signed)
   837  	if err != nil {
   838  		return nil, err
   839  	}
   840  	if sender != address {
   841  		return nil, fmt.Errorf("signer mismatch: expected %s, got %s", address.Hex(), sender.Hex())
   842  	}
   843  	return signed, nil
   844  }
   845  
   846  // ledgerExchange performs a data exchange with the Ledger wallet, sending it a
   847  // message and retrieving the response.
   848  //
   849  // The common transport header is defined as follows:
   850  //
   851  //  Description                           | Length
   852  //  --------------------------------------+----------
   853  //  Communication channel ID (big endian) | 2 bytes
   854  //  Command tag                           | 1 byte
   855  //  Packet sequence index (big endian)    | 2 bytes
   856  //  Payload                               | arbitrary
   857  //
   858  // The Communication channel ID allows commands multiplexing over the same
   859  // physical link. It is not used for the time being, and should be set to 0101
   860  // to avoid compatibility issues with implementations ignoring a leading 00 byte.
   861  //
   862  // The Command tag describes the message content. Use TAG_APDU (0x05) for standard
   863  // APDU payloads, or TAG_PING (0x02) for a simple link test.
   864  //
   865  // The Packet sequence index describes the current sequence for fragmented payloads.
   866  // The first fragment index is 0x00.
   867  //
   868  // APDU Command payloads are encoded as follows:
   869  //
   870  //  Description              | Length
   871  //  -----------------------------------
   872  //  APDU length (big endian) | 2 bytes
   873  //  APDU CLA                 | 1 byte
   874  //  APDU INS                 | 1 byte
   875  //  APDU P1                  | 1 byte
   876  //  APDU P2                  | 1 byte
   877  //  APDU length              | 1 byte
   878  //  Optional APDU data       | arbitrary
   879  func (w *ledgerWallet) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
   880  	// Construct the message payload, possibly split into multiple chunks
   881  	apdu := make([]byte, 2, 7+len(data))
   882  
   883  	binary.BigEndian.PutUint16(apdu, uint16(5+len(data)))
   884  	apdu = append(apdu, []byte{0xe0, byte(opcode), byte(p1), byte(p2), byte(len(data))}...)
   885  	apdu = append(apdu, data...)
   886  
   887  	// Stream all the chunks to the device
   888  	header := []byte{0x01, 0x01, 0x05, 0x00, 0x00} // Channel ID and command tag appended
   889  	chunk := make([]byte, 64)
   890  	space := len(chunk) - len(header)
   891  
   892  	for i := 0; len(apdu) > 0; i++ {
   893  		// Construct the new message to stream
   894  		chunk = append(chunk[:0], header...)
   895  		binary.BigEndian.PutUint16(chunk[3:], uint16(i))
   896  
   897  		if len(apdu) > space {
   898  			chunk = append(chunk, apdu[:space]...)
   899  			apdu = apdu[space:]
   900  		} else {
   901  			chunk = append(chunk, apdu...)
   902  			apdu = nil
   903  		}
   904  		// Send over to the device
   905  		if glog.V(logger.Detail) {
   906  			glog.Infof("-> %03d.%03d: %x", w.device.Bus, w.device.Address, chunk)
   907  		}
   908  		if _, err := w.input.Write(chunk); err != nil {
   909  			return nil, err
   910  		}
   911  	}
   912  	// Stream the reply back from the wallet in 64 byte chunks
   913  	var reply []byte
   914  	chunk = chunk[:64] // Yeah, we surely have enough space
   915  	for {
   916  		// Read the next chunk from the Ledger wallet
   917  		if _, err := io.ReadFull(w.output, chunk); err != nil {
   918  			return nil, err
   919  		}
   920  		if glog.V(logger.Detail) {
   921  			glog.Infof("<- %03d.%03d: %x", w.device.Bus, w.device.Address, chunk)
   922  		}
   923  		// Make sure the transport header matches
   924  		if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 {
   925  			return nil, errReplyInvalidHeader
   926  		}
   927  		// If it's the first chunk, retrieve the total message length
   928  		var payload []byte
   929  
   930  		if chunk[3] == 0x00 && chunk[4] == 0x00 {
   931  			reply = make([]byte, 0, int(binary.BigEndian.Uint16(chunk[5:7])))
   932  			payload = chunk[7:]
   933  		} else {
   934  			payload = chunk[5:]
   935  		}
   936  		// Append to the reply and stop when filled up
   937  		if left := cap(reply) - len(reply); left > len(payload) {
   938  			reply = append(reply, payload...)
   939  		} else {
   940  			reply = append(reply, payload[:left]...)
   941  			break
   942  		}
   943  	}
   944  	return reply[:len(reply)-2], nil
   945  }