code: func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
  	w.stateLock.RLock() // Comms have own mutex, this is for the state fields
  	defer w.stateLock.RUnlock()
  
  	// If the wallet is closed, abort
  	if w.device == nil {
  		return nil, accounts.ErrWalletClosed
  	}
  	// Make sure the requested account is contained within
  	path, ok := w.paths[account.Address]
  	if !ok {
  		return nil, accounts.ErrUnknownAccount
  	}
  	// All infos gathered and metadata checks out, request signing
  	<-w.commsLock
  	defer func() { w.commsLock <- struct{}{} }()
  
  	// Ensure the device isn't screwed with while user confirmation is pending
  	// TODO(karalabe): remove if hotplug lands on Windows
  	w.hub.commsLock.Lock()
  	w.hub.commsPend++
  	w.hub.commsLock.Unlock()
  
  	defer func() {
  		w.hub.commsLock.Lock()
  		w.hub.commsPend--
  		w.hub.commsLock.Unlock()
  	}()
  	// Sign the transaction and verify the sender to avoid hardware fault surprises
  	sender, signed, err := w.driver.SignTx(path, tx, chainID)
  	if err != nil {
  		return nil, err
  	}
  	if sender != account.Address {
  		return nil, fmt.Errorf("signer mismatch: expected %s, got %s", account.Address.Hex(), sender.Hex())
  	}
  	return signed, nil
  }
docs: // SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
  // wallet to request a confirmation from the user. It returns either the signed
  // transaction or a failure if the user denied the transaction.
  //
  // Note, if the version of the Ethereum application running on the Ledger wallet is
  // too old to sign EIP-155 transactions, but such is requested nonetheless, an error
  // will be returned opposed to silently signing in Homestead mode.