github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/usbwallet/wallet.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //软件包usbwallet实现对USB硬件钱包的支持。
    26  package usbwallet
    27  
    28  import (
    29  	"context"
    30  	"fmt"
    31  	"io"
    32  	"math/big"
    33  	"sync"
    34  	"time"
    35  
    36  	ethereum "github.com/ethereum/go-ethereum"
    37  	"github.com/ethereum/go-ethereum/accounts"
    38  	"github.com/ethereum/go-ethereum/common"
    39  	"github.com/ethereum/go-ethereum/core/types"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/karalabe/hid"
    42  )
    43  
    44  //钱包健康检查之间检测USB拔出的最长时间。
    45  const heartbeatCycle = time.Second
    46  
    47  //在自派生尝试之间等待的最短时间,即使用户
    48  //像疯了一样申请账户。
    49  const selfDeriveThrottling = time.Second
    50  
    51  //驱动程序定义特定于供应商的功能硬件钱包实例
    52  //必须实施以允许在钱包生命周期管理中使用它们。
    53  type driver interface {
    54  //状态返回文本状态以帮助用户处于
    55  //钱包。它还返回一个错误,指示钱包可能发生的任何故障。
    56  //遇到。
    57  	Status() (string, error)
    58  
    59  //open初始化对钱包实例的访问。passphrase参数可以
    60  //或者不可用于特定钱包实例的实现。
    61  	Open(device io.ReadWriter, passphrase string) error
    62  
    63  //关闭释放打开钱包实例持有的任何资源。
    64  	Close() error
    65  
    66  //Heartbeat对硬件钱包执行健全检查,以查看是否
    67  //仍然在线且健康。
    68  	Heartbeat() error
    69  
    70  //派生向USB设备发送派生请求并返回以太坊
    71  //地址位于该路径上。
    72  	Derive(path accounts.DerivationPath) (common.Address, error)
    73  
    74  //signtx将事务发送到USB设备并等待用户确认
    75  //或者拒绝交易。
    76  	SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error)
    77  }
    78  
    79  //Wallet代表所有USB硬件共享的通用功能
    80  //防止重新实施相同复杂维护机制的钱包
    81  //对于不同的供应商。
    82  type wallet struct {
    83  hub    *Hub          //USB集线器扫描
    84  driver driver        //底层设备操作的硬件实现
    85  url    *accounts.URL //唯一标识此钱包的文本URL
    86  
    87  info   hid.DeviceInfo //已知的USB设备有关钱包的信息
    88  device *hid.Device    //USB设备作为硬件钱包做广告
    89  
    90  accounts []accounts.Account                         //固定在硬件钱包上的派生帐户列表
    91  paths    map[common.Address]accounts.DerivationPath //签名操作的已知派生路径
    92  
    93  deriveNextPath accounts.DerivationPath   //帐户自动发现的下一个派生路径
    94  deriveNextAddr common.Address            //自动发现的下一个派生帐户地址
    95  deriveChain    ethereum.ChainStateReader //区块链状态阅读器发现用过的账户
    96  deriveReq      chan chan struct{}        //请求自派生的通道
    97  deriveQuit     chan chan error           //终止自导数的通道
    98  
    99  	healthQuit chan chan error
   100  
   101  //锁定硬件钱包有点特别。因为硬件设备比较低
   102  //执行时,与他们的任何通信可能需要
   103  //时间。更糟糕的是,等待用户确认可能需要很长时间,
   104  //但在这期间必须保持独家沟通。锁定整个钱包
   105  //然而,在同一时间内,系统中任何不需要的部分都会停止运行。
   106  //要进行通信,只需阅读一些状态(例如列出帐户)。
   107  //
   108  //因此,硬件钱包需要两个锁才能正常工作。国家
   109  //锁可用于保护钱包软件侧的内部状态,其中
   110  //不得在硬件通信期间独占。交流
   111  //锁可以用来实现对设备本身的独占访问,这一个
   112  //但是,应该允许“跳过”等待可能需要的操作
   113  //使用该设备,但也可以不使用(例如,帐户自派生)。
   114  //
   115  //因为我们有两个锁,所以必须知道如何正确使用它们:
   116  //-通信要求“device”不更改,因此获取
   117  //commslock应该在有状态锁之后完成。
   118  //-通信不得禁用对钱包状态的读取访问,因此
   119  //只能将*read*锁保持为statelock。
   120  commsLock chan struct{} //在不保持状态锁定的情况下,USB通信的互斥(buf=1)
   121  stateLock sync.RWMutex  //保护对wallet结构字段的读写访问
   122  
   123  log log.Logger //上下文记录器,用其ID标记基
   124  }
   125  
   126  //url实现accounts.wallet,返回usb硬件设备的url。
   127  func (w *wallet) URL() accounts.URL {
   128  return *w.url //不可变,不需要锁
   129  }
   130  
   131  //状态实现accounts.wallet,从
   132  //底层特定于供应商的硬件钱包实现。
   133  func (w *wallet) Status() (string, error) {
   134  w.stateLock.RLock() //没有设备通信,状态锁就足够了
   135  	defer w.stateLock.RUnlock()
   136  
   137  	status, failure := w.driver.Status()
   138  	if w.device == nil {
   139  		return "Closed", failure
   140  	}
   141  	return status, failure
   142  }
   143  
   144  //打开implements accounts.wallet,尝试打开与
   145  //硬件钱包。
   146  func (w *wallet) Open(passphrase string) error {
   147  w.stateLock.Lock() //状态锁已经足够了,因为此时还没有连接
   148  	defer w.stateLock.Unlock()
   149  
   150  //如果设备已打开一次,请拒绝重试
   151  	if w.paths != nil {
   152  		return accounts.ErrWalletAlreadyOpen
   153  	}
   154  //确保实际设备连接仅完成一次
   155  	if w.device == nil {
   156  		device, err := w.info.Open()
   157  		if err != nil {
   158  			return err
   159  		}
   160  		w.device = device
   161  		w.commsLock = make(chan struct{}, 1)
   162  w.commsLock <- struct{}{} //使能锁定
   163  	}
   164  //将设备初始化委托给基础驱动程序
   165  	if err := w.driver.Open(w.device, passphrase); err != nil {
   166  		return err
   167  	}
   168  //连接成功,开始生命周期管理
   169  	w.paths = make(map[common.Address]accounts.DerivationPath)
   170  
   171  	w.deriveReq = make(chan chan struct{})
   172  	w.deriveQuit = make(chan chan error)
   173  	w.healthQuit = make(chan chan error)
   174  
   175  	go w.heartbeat()
   176  	go w.selfDerive()
   177  
   178  //通知任何收听钱包事件的人可以访问新设备
   179  	go w.hub.updateFeed.Send(accounts.WalletEvent{Wallet: w, Kind: accounts.WalletOpened})
   180  
   181  	return nil
   182  }
   183  
   184  //心跳是一个健康检查循环,用于USB钱包定期验证
   185  //它们是否仍然存在,或者是否出现故障。
   186  func (w *wallet) heartbeat() {
   187  	w.log.Debug("USB wallet health-check started")
   188  	defer w.log.Debug("USB wallet health-check stopped")
   189  
   190  //执行心跳检查,直到终止或出错
   191  	var (
   192  		errc chan error
   193  		err  error
   194  	)
   195  	for errc == nil && err == nil {
   196  //等待直到请求终止或心跳周期到达
   197  		select {
   198  		case errc = <-w.healthQuit:
   199  //请求终止
   200  			continue
   201  		case <-time.After(heartbeatCycle):
   202  //心跳时间
   203  		}
   204  //执行微小的数据交换以查看响应
   205  		w.stateLock.RLock()
   206  		if w.device == nil {
   207  //在等待锁时终止
   208  			w.stateLock.RUnlock()
   209  			continue
   210  		}
   211  <-w.commsLock //解析版本时不锁定状态
   212  		err = w.driver.Heartbeat()
   213  		w.commsLock <- struct{}{}
   214  		w.stateLock.RUnlock()
   215  
   216  		if err != nil {
   217  w.stateLock.Lock() //锁定状态以将钱包撕下
   218  			w.close()
   219  			w.stateLock.Unlock()
   220  		}
   221  //忽略与硬件无关的错误
   222  		err = nil
   223  	}
   224  //如果出现错误,请等待终止
   225  	if err != nil {
   226  		w.log.Debug("USB wallet health-check failed", "err", err)
   227  		errc = <-w.healthQuit
   228  	}
   229  	errc <- err
   230  }
   231  
   232  //关闭机具帐户。钱包,关闭设备的USB连接。
   233  func (w *wallet) Close() error {
   234  //确保钱包已打开
   235  	w.stateLock.RLock()
   236  	hQuit, dQuit := w.healthQuit, w.deriveQuit
   237  	w.stateLock.RUnlock()
   238  
   239  //终止健康检查
   240  	var herr error
   241  	if hQuit != nil {
   242  		errc := make(chan error)
   243  		hQuit <- errc
   244  herr = <-errc //保存供以后使用,我们*必须*关闭USB
   245  	}
   246  //终止自派生
   247  	var derr error
   248  	if dQuit != nil {
   249  		errc := make(chan error)
   250  		dQuit <- errc
   251  derr = <-errc //保存供以后使用,我们*必须*关闭USB
   252  	}
   253  //终止设备连接
   254  	w.stateLock.Lock()
   255  	defer w.stateLock.Unlock()
   256  
   257  	w.healthQuit = nil
   258  	w.deriveQuit = nil
   259  	w.deriveReq = nil
   260  
   261  	if err := w.close(); err != nil {
   262  		return err
   263  	}
   264  	if herr != nil {
   265  		return herr
   266  	}
   267  	return derr
   268  }
   269  
   270  //Close是内部钱包闭合器,用于终止USB连接和
   271  //将所有字段重置为默认值。
   272  //
   273  //注意,CLOSE假设状态锁被保持!
   274  func (w *wallet) close() error {
   275  //允许重复关闭,特别是在运行状况检查失败时
   276  	if w.device == nil {
   277  		return nil
   278  	}
   279  //关闭设备,清除所有内容,然后返回
   280  	w.device.Close()
   281  	w.device = nil
   282  
   283  	w.accounts, w.paths = nil, nil
   284  	w.driver.Close()
   285  
   286  	return nil
   287  }
   288  
   289  //帐户实现帐户。钱包,返回固定到的帐户列表
   290  //USB硬件钱包。如果启用了自派生,则帐户列表为
   291  //根据当前链状态定期扩展。
   292  func (w *wallet) Accounts() []accounts.Account {
   293  //如果正在运行,尝试自派生
   294  	reqc := make(chan struct{}, 1)
   295  	select {
   296  	case w.deriveReq <- reqc:
   297  //已接受自派生请求,请稍候
   298  		<-reqc
   299  	default:
   300  //脱机自派生、受限或忙碌、跳过
   301  	}
   302  //
   303  	w.stateLock.RLock()
   304  	defer w.stateLock.RUnlock()
   305  
   306  	cpy := make([]accounts.Account, len(w.accounts))
   307  	copy(cpy, w.accounts)
   308  	return cpy
   309  }
   310  
   311  //selfderive是一个帐户派生循环,在请求时尝试查找
   312  //新的非零账户。
   313  func (w *wallet) selfDerive() {
   314  	w.log.Debug("USB wallet self-derivation started")
   315  	defer w.log.Debug("USB wallet self-derivation stopped")
   316  
   317  //执行自派生直到终止或出错
   318  	var (
   319  		reqc chan struct{}
   320  		errc chan error
   321  		err  error
   322  	)
   323  	for errc == nil && err == nil {
   324  //等待直到请求派生或终止
   325  		select {
   326  		case errc = <-w.deriveQuit:
   327  //请求终止
   328  			continue
   329  		case reqc = <-w.deriveReq:
   330  //已请求帐户发现
   331  		}
   332  //派生需要链和设备访问,如果不可用则跳过
   333  		w.stateLock.RLock()
   334  		if w.device == nil || w.deriveChain == nil {
   335  			w.stateLock.RUnlock()
   336  			reqc <- struct{}{}
   337  			continue
   338  		}
   339  		select {
   340  		case <-w.commsLock:
   341  		default:
   342  			w.stateLock.RUnlock()
   343  			reqc <- struct{}{}
   344  			continue
   345  		}
   346  //获取设备锁,派生下一批帐户
   347  		var (
   348  			accs  []accounts.Account
   349  			paths []accounts.DerivationPath
   350  
   351  			nextAddr = w.deriveNextAddr
   352  			nextPath = w.deriveNextPath
   353  
   354  			context = context.Background()
   355  		)
   356  		for empty := false; !empty; {
   357  //检索下一个派生的以太坊帐户
   358  			if nextAddr == (common.Address{}) {
   359  				if nextAddr, err = w.driver.Derive(nextPath); err != nil {
   360  					w.log.Warn("USB wallet account derivation failed", "err", err)
   361  					break
   362  				}
   363  			}
   364  //对照当前链状态检查帐户状态
   365  			var (
   366  				balance *big.Int
   367  				nonce   uint64
   368  			)
   369  			balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
   370  			if err != nil {
   371  				w.log.Warn("USB wallet balance retrieval failed", "err", err)
   372  				break
   373  			}
   374  			nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
   375  			if err != nil {
   376  				w.log.Warn("USB wallet nonce retrieval failed", "err", err)
   377  				break
   378  			}
   379  //如果下一个帐户为空,请停止自派生,但仍要添加它。
   380  			if balance.Sign() == 0 && nonce == 0 {
   381  				empty = true
   382  			}
   383  //我们刚刚自己创建了一个新帐户,开始在本地跟踪它
   384  			path := make(accounts.DerivationPath, len(nextPath))
   385  			copy(path[:], nextPath[:])
   386  			paths = append(paths, path)
   387  
   388  			account := accounts.Account{
   389  				Address: nextAddr,
   390  				URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   391  			}
   392  			accs = append(accs, account)
   393  
   394  //为新帐户(或以前为空的帐户)向用户显示日志消息
   395  			if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
   396  				w.log.Info("USB wallet discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce)
   397  			}
   398  //获取下一个潜在帐户
   399  			if !empty {
   400  				nextAddr = common.Address{}
   401  				nextPath[len(nextPath)-1]++
   402  			}
   403  		}
   404  //自派生完成,释放装置锁
   405  		w.commsLock <- struct{}{}
   406  		w.stateLock.RUnlock()
   407  
   408  //插入成功派生的任何帐户
   409  		w.stateLock.Lock()
   410  		for i := 0; i < len(accs); i++ {
   411  			if _, ok := w.paths[accs[i].Address]; !ok {
   412  				w.accounts = append(w.accounts, accs[i])
   413  				w.paths[accs[i].Address] = paths[i]
   414  			}
   415  		}
   416  //向前移动自派生
   417  //TODO(卡拉贝拉):不要覆盖wallet.self派生的更改
   418  		w.deriveNextAddr = nextAddr
   419  		w.deriveNextPath = nextPath
   420  		w.stateLock.Unlock()
   421  
   422  //一段时间后通知用户终止和循环(以避免损坏)
   423  		reqc <- struct{}{}
   424  		if err == nil {
   425  			select {
   426  			case errc = <-w.deriveQuit:
   427  //请求终止,中止
   428  			case <-time.After(selfDeriveThrottling):
   429  //等得够久,愿意自己再推导一次
   430  			}
   431  		}
   432  	}
   433  //如果出现错误,请等待终止
   434  	if err != nil {
   435  		w.log.Debug("USB wallet self-derivation failed", "err", err)
   436  		errc = <-w.deriveQuit
   437  	}
   438  	errc <- err
   439  }
   440  
   441  //包含implements accounts.wallet,返回特定帐户是否为
   442  //或未固定到此钱包实例中。尽管我们可以尝试解决
   443  //取消固定帐户,这将是一个不可忽略的硬件操作。
   444  func (w *wallet) Contains(account accounts.Account) bool {
   445  	w.stateLock.RLock()
   446  	defer w.stateLock.RUnlock()
   447  
   448  	_, exists := w.paths[account.Address]
   449  	return exists
   450  }
   451  
   452  //派生实现accounts.wallet,在特定的
   453  //派生路径。如果pin设置为true,则帐户将添加到列表中
   454  //个跟踪帐户。
   455  func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
   456  //如果成功,尝试派生实际帐户并更新其URL
   457  w.stateLock.RLock() //避免设备在派生过程中消失
   458  
   459  	if w.device == nil {
   460  		w.stateLock.RUnlock()
   461  		return accounts.Account{}, accounts.ErrWalletClosed
   462  	}
   463  <-w.commsLock //避免并行硬件访问
   464  	address, err := w.driver.Derive(path)
   465  	w.commsLock <- struct{}{}
   466  
   467  	w.stateLock.RUnlock()
   468  
   469  //如果发生错误或未请求固定,请返回
   470  	if err != nil {
   471  		return accounts.Account{}, err
   472  	}
   473  	account := accounts.Account{
   474  		Address: address,
   475  		URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   476  	}
   477  	if !pin {
   478  		return account, nil
   479  	}
   480  //
   481  	w.stateLock.Lock()
   482  	defer w.stateLock.Unlock()
   483  
   484  	if _, ok := w.paths[address]; !ok {
   485  		w.accounts = append(w.accounts, account)
   486  		w.paths[address] = path
   487  	}
   488  	return account, nil
   489  }
   490  
   491  //selfderive实现accounts.wallet,尝试发现
   492  //用户以前使用过(基于链状态),但他/她没有使用过
   493  //手动明确地固定到钱包。为了避免链头监控,请自行
   494  //派生仅在帐户列表期间运行(甚至在随后被限制)。
   495  func (w *wallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {
   496  	w.stateLock.Lock()
   497  	defer w.stateLock.Unlock()
   498  
   499  	w.deriveNextPath = make(accounts.DerivationPath, len(base))
   500  	copy(w.deriveNextPath[:], base[:])
   501  
   502  	w.deriveNextAddr = common.Address{}
   503  	w.deriveChain = chain
   504  }
   505  
   506  //signhash实现accounts.wallet,但是签名任意数据不是
   507  //支持硬件钱包,因此此方法将始终返回错误。
   508  func (w *wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) {
   509  	return nil, accounts.ErrNotSupported
   510  }
   511  
   512  //signtx实现accounts.wallet。它将交易发送到分类帐
   513  //要求用户确认的钱包。它返回已签名的
   514  //如果用户拒绝该事务,则为事务或失败。
   515  //
   516  //注意,如果运行在Ledger钱包上的以太坊应用程序的版本是
   517  //太旧,无法签署EIP-155交易,但要求这样做,还是有错误
   518  //将返回,而不是在宅基地模式中静默签名。
   519  func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   520  w.stateLock.RLock() //通信有自己的互斥,这是用于状态字段
   521  	defer w.stateLock.RUnlock()
   522  
   523  //如果钱包关闭,中止
   524  	if w.device == nil {
   525  		return nil, accounts.ErrWalletClosed
   526  	}
   527  //确保请求的帐户包含在
   528  	path, ok := w.paths[account.Address]
   529  	if !ok {
   530  		return nil, accounts.ErrUnknownAccount
   531  	}
   532  //收集的所有信息和元数据均已签出,请求签名
   533  	<-w.commsLock
   534  	defer func() { w.commsLock <- struct{}{} }()
   535  
   536  //在等待用户确认时,确保设备没有拧紧。
   537  //TODO(karalabe):如果热插拔落在Windows上,则移除。
   538  	w.hub.commsLock.Lock()
   539  	w.hub.commsPend++
   540  	w.hub.commsLock.Unlock()
   541  
   542  	defer func() {
   543  		w.hub.commsLock.Lock()
   544  		w.hub.commsPend--
   545  		w.hub.commsLock.Unlock()
   546  	}()
   547  //签署事务并验证发送方以避免硬件故障意外
   548  	sender, signed, err := w.driver.SignTx(path, tx, chainID)
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  	if sender != account.Address {
   553  		return nil, fmt.Errorf("signer mismatch: expected %s, got %s", account.Address.Hex(), sender.Hex())
   554  	}
   555  	return signed, nil
   556  }
   557  
   558  //signhashwithpassphrase实现accounts.wallet,但是任意签名
   559  //分类帐钱包不支持数据,因此此方法将始终返回
   560  //一个错误。
   561  func (w *wallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
   562  	return w.SignHash(account, hash)
   563  }
   564  
   565  //signtxwithpassphrase实现accounts.wallet,尝试对给定的
   566  //使用密码短语作为额外身份验证的给定帐户的事务。
   567  //由于USB钱包不依赖密码,因此这些密码会被静默忽略。
   568  func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   569  	return w.SignTx(account, tx, chainID)
   570  }