github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/usbwallet/trezor.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  //此文件包含用于与Trezor硬件交互的实现
    26  //钱包。有线协议规范可在Satoshilabs网站上找到:
    27  //https://doc.satoshilabs.com/trezor-tech/api-protobuf.html网站
    28  
    29  package usbwallet
    30  
    31  import (
    32  	"encoding/binary"
    33  	"errors"
    34  	"fmt"
    35  	"io"
    36  	"math/big"
    37  
    38  	"github.com/ethereum/go-ethereum/accounts"
    39  	"github.com/ethereum/go-ethereum/accounts/usbwallet/internal/trezor"
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"github.com/ethereum/go-ethereum/common/hexutil"
    42  	"github.com/ethereum/go-ethereum/core/types"
    43  	"github.com/ethereum/go-ethereum/log"
    44  	"github.com/golang/protobuf/proto"
    45  )
    46  
    47  //如果打开trezor需要PIN代码,则返回errtrezorpinneed。在
    48  //在这种情况下,调用应用程序应显示一个pinpad并将
    49  //编码的密码短语。
    50  var ErrTrezorPINNeeded = errors.New("trezor: pin needed")
    51  
    52  //errTrezorreplyinvalidHeader是Trezor数据交换返回的错误消息
    53  //如果设备回复的标题不匹配。这通常意味着设备
    54  //处于浏览器模式。
    55  var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
    56  
    57  //Trezordriver实现了与Trezor硬件钱包的通信。
    58  type trezorDriver struct {
    59  device  io.ReadWriter //通过USB设备连接进行通信
    60  version [3]uint32     //Trezor固件的当前版本
    61  label   string        //Trezor设备的当前文本标签
    62  pinwait bool          //标记设备是否正在等待PIN输入
    63  failure error         //任何使设备无法使用的故障
    64  log     log.Logger    //上下文记录器,用其ID标记Trezor
    65  }
    66  
    67  //NewTrezorDriver创建Trezor USB协议驱动程序的新实例。
    68  func newTrezorDriver(logger log.Logger) driver {
    69  	return &trezorDriver{
    70  		log: logger,
    71  	}
    72  }
    73  
    74  //状态实现帐户。钱包,无论Trezor是否打开、关闭
    75  //或者以太坊应用程序是否没有启动。
    76  func (w *trezorDriver) Status() (string, error) {
    77  	if w.failure != nil {
    78  		return fmt.Sprintf("Failed: %v", w.failure), w.failure
    79  	}
    80  	if w.device == nil {
    81  		return "Closed", w.failure
    82  	}
    83  	if w.pinwait {
    84  		return fmt.Sprintf("Trezor v%d.%d.%d '%s' waiting for PIN", w.version[0], w.version[1], w.version[2], w.label), w.failure
    85  	}
    86  	return fmt.Sprintf("Trezor v%d.%d.%d '%s' online", w.version[0], w.version[1], w.version[2], w.label), w.failure
    87  }
    88  
    89  //open实现usbwallet.driver,尝试初始化到的连接
    90  //Trezor硬件钱包。初始化trezor是一个两阶段操作:
    91  //*第一阶段是初始化连接并读取钱包的
    92  //特征。如果提供的密码短语为空,则调用此阶段。这个
    93  //设备将显示精确定位结果,并返回相应的
    94  //通知用户需要第二个打开阶段时出错。
    95  //*第二阶段是解锁对trezor的访问,由
    96  //用户实际上提供了一个将键盘键盘映射到PIN的密码短语
    97  //用户数(根据显示的精确定位随机排列)。
    98  func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
    99  	w.device, w.failure = device, nil
   100  
   101  //如果请求阶段1,初始化连接并等待用户回调
   102  	if passphrase == "" {
   103  //如果我们已经在等待密码输入,Insta返回
   104  		if w.pinwait {
   105  			return ErrTrezorPINNeeded
   106  		}
   107  //初始化与设备的连接
   108  		features := new(trezor.Features)
   109  		if _, err := w.trezorExchange(&trezor.Initialize{}, features); err != nil {
   110  			return err
   111  		}
   112  		w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()}
   113  		w.label = features.GetLabel()
   114  
   115  //执行手动ping,强制设备请求其PIN
   116  		askPin := true
   117  		res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin}, new(trezor.PinMatrixRequest), new(trezor.Success))
   118  		if err != nil {
   119  			return err
   120  		}
   121  //只有在设备尚未解锁时才返回PIN请求
   122  		if res == 1 {
   123  return nil //设备以trezor.success响应。
   124  		}
   125  		w.pinwait = true
   126  		return ErrTrezorPINNeeded
   127  	}
   128  //第2阶段要求实际输入PIN
   129  	w.pinwait = false
   130  
   131  	if _, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success)); err != nil {
   132  		w.failure = err
   133  		return err
   134  	}
   135  	return nil
   136  }
   137  
   138  //close实现usbwallet.driver,清理和元数据维护在
   139  //Trezor司机。
   140  func (w *trezorDriver) Close() error {
   141  	w.version, w.label, w.pinwait = [3]uint32{}, "", false
   142  	return nil
   143  }
   144  
   145  //heartbeat实现usbwallet.driver,对
   146  //Trezor看看它是否仍然在线。
   147  func (w *trezorDriver) Heartbeat() error {
   148  	if _, err := w.trezorExchange(&trezor.Ping{}, new(trezor.Success)); err != nil {
   149  		w.failure = err
   150  		return err
   151  	}
   152  	return nil
   153  }
   154  
   155  //派生实现usbwallet.driver,向trezor发送派生请求
   156  //并返回位于该派生路径上的以太坊地址。
   157  func (w *trezorDriver) Derive(path accounts.DerivationPath) (common.Address, error) {
   158  	return w.trezorDerive(path)
   159  }
   160  
   161  //signtx实现usbwallet.driver,将事务发送到trezor并
   162  //正在等待用户确认或拒绝该事务。
   163  func (w *trezorDriver) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
   164  	if w.device == nil {
   165  		return common.Address{}, nil, accounts.ErrWalletClosed
   166  	}
   167  	return w.trezorSign(path, tx, chainID)
   168  }
   169  
   170  //TrezorDrive向Trezor设备发送派生请求并返回
   171  //以太坊地址位于该路径上。
   172  func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, error) {
   173  	address := new(trezor.EthereumAddress)
   174  	if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
   175  		return common.Address{}, err
   176  	}
   177  	return common.BytesToAddress(address.GetAddress()), nil
   178  }
   179  
   180  //Trezorsign将事务发送到Trezor钱包,并等待用户
   181  //确认或拒绝交易。
   182  func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
   183  //创建事务启动消息
   184  	data := tx.Data()
   185  	length := uint32(len(data))
   186  
   187  	request := &trezor.EthereumSignTx{
   188  		AddressN:   derivationPath,
   189  		Nonce:      new(big.Int).SetUint64(tx.Nonce()).Bytes(),
   190  		GasPrice:   tx.GasPrice().Bytes(),
   191  		GasLimit:   new(big.Int).SetUint64(tx.Gas()).Bytes(),
   192  		Value:      tx.Value().Bytes(),
   193  		DataLength: &length,
   194  	}
   195  	if to := tx.To(); to != nil {
   196  request.To = (*to)[:] //非合同部署,显式设置收件人
   197  	}
   198  if length > 1024 { //如果请求发送数据块
   199  		request.DataInitialChunk, data = data[:1024], data[1024:]
   200  	} else {
   201  		request.DataInitialChunk, data = data, nil
   202  	}
   203  if chainID != nil { //EIP-155事务,显式设置链ID(仅支持32位!?)
   204  		id := uint32(chainID.Int64())
   205  		request.ChainId = &id
   206  	}
   207  //发送初始消息和流内容,直到返回签名
   208  	response := new(trezor.EthereumTxRequest)
   209  	if _, err := w.trezorExchange(request, response); err != nil {
   210  		return common.Address{}, nil, err
   211  	}
   212  	for response.DataLength != nil && int(*response.DataLength) <= len(data) {
   213  		chunk := data[:*response.DataLength]
   214  		data = data[*response.DataLength:]
   215  
   216  		if _, err := w.trezorExchange(&trezor.EthereumTxAck{DataChunk: chunk}, response); err != nil {
   217  			return common.Address{}, nil, err
   218  		}
   219  	}
   220  //提取以太坊签名并进行健全性验证
   221  	if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 || response.GetSignatureV() == 0 {
   222  		return common.Address{}, nil, errors.New("reply lacks signature")
   223  	}
   224  	signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV()))
   225  
   226  //基于链ID创建正确的签名者和签名转换
   227  	var signer types.Signer
   228  	if chainID == nil {
   229  		signer = new(types.HomesteadSigner)
   230  	} else {
   231  		signer = types.NewEIP155Signer(chainID)
   232  		signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
   233  	}
   234  //在事务中插入最终签名并检查发送者的健全性
   235  	signed, err := tx.WithSignature(signer, signature)
   236  	if err != nil {
   237  		return common.Address{}, nil, err
   238  	}
   239  	sender, err := types.Sender(signer, signed)
   240  	if err != nil {
   241  		return common.Address{}, nil, err
   242  	}
   243  	return sender, signed, nil
   244  }
   245  
   246  //trezor exchange执行与trezor钱包的数据交换,并向其发送
   247  //并检索响应。如果可能有多个响应,则
   248  //方法还将返回所用目标对象的索引。
   249  func (w *trezorDriver) trezorExchange(req proto.Message, results ...proto.Message) (int, error) {
   250  //构造原始消息有效负载以进行分组
   251  	data, err := proto.Marshal(req)
   252  	if err != nil {
   253  		return 0, err
   254  	}
   255  	payload := make([]byte, 8+len(data))
   256  	copy(payload, []byte{0x23, 0x23})
   257  	binary.BigEndian.PutUint16(payload[2:], trezor.Type(req))
   258  	binary.BigEndian.PutUint32(payload[4:], uint32(len(data)))
   259  	copy(payload[8:], data)
   260  
   261  //将所有块流式传输到设备
   262  	chunk := make([]byte, 64)
   263  chunk[0] = 0x3f //报告ID幻数
   264  
   265  	for len(payload) > 0 {
   266  //构造新消息到流,如果需要,用零填充
   267  		if len(payload) > 63 {
   268  			copy(chunk[1:], payload[:63])
   269  			payload = payload[63:]
   270  		} else {
   271  			copy(chunk[1:], payload)
   272  			copy(chunk[1+len(payload):], make([]byte, 63-len(payload)))
   273  			payload = nil
   274  		}
   275  //发送到设备
   276  		w.log.Trace("Data chunk sent to the Trezor", "chunk", hexutil.Bytes(chunk))
   277  		if _, err := w.device.Write(chunk); err != nil {
   278  			return 0, err
   279  		}
   280  	}
   281  //将回复从钱包中以64字节的块流式返回
   282  	var (
   283  		kind  uint16
   284  		reply []byte
   285  	)
   286  	for {
   287  //从Trezor钱包中读取下一块
   288  		if _, err := io.ReadFull(w.device, chunk); err != nil {
   289  			return 0, err
   290  		}
   291  		w.log.Trace("Data chunk received from the Trezor", "chunk", hexutil.Bytes(chunk))
   292  
   293  //确保传输头匹配
   294  		if chunk[0] != 0x3f || (len(reply) == 0 && (chunk[1] != 0x23 || chunk[2] != 0x23)) {
   295  			return 0, errTrezorReplyInvalidHeader
   296  		}
   297  //如果是第一个块,则检索回复消息类型和总消息长度
   298  		var payload []byte
   299  
   300  		if len(reply) == 0 {
   301  			kind = binary.BigEndian.Uint16(chunk[3:5])
   302  			reply = make([]byte, 0, int(binary.BigEndian.Uint32(chunk[5:9])))
   303  			payload = chunk[9:]
   304  		} else {
   305  			payload = chunk[1:]
   306  		}
   307  //追加到答复并在填写时停止
   308  		if left := cap(reply) - len(reply); left > len(payload) {
   309  			reply = append(reply, payload...)
   310  		} else {
   311  			reply = append(reply, payload[:left]...)
   312  			break
   313  		}
   314  	}
   315  //尝试将答复解析为请求的答复消息
   316  	if kind == uint16(trezor.MessageType_MessageType_Failure) {
   317  //Trezor返回一个失败,提取并返回消息
   318  		failure := new(trezor.Failure)
   319  		if err := proto.Unmarshal(reply, failure); err != nil {
   320  			return 0, err
   321  		}
   322  		return 0, errors.New("trezor: " + failure.GetMessage())
   323  	}
   324  	if kind == uint16(trezor.MessageType_MessageType_ButtonRequest) {
   325  //Trezor正在等待用户确认、确认并等待下一条消息
   326  		return w.trezorExchange(&trezor.ButtonAck{}, results...)
   327  	}
   328  	for i, res := range results {
   329  		if trezor.Type(res) == kind {
   330  			return i, proto.Unmarshal(reply, res)
   331  		}
   332  	}
   333  	expected := make([]string, len(results))
   334  	for i, res := range results {
   335  		expected[i] = trezor.Name(trezor.Type(res))
   336  	}
   337  	return 0, fmt.Errorf("trezor: expected reply types %s, got %s", expected, trezor.Name(kind))
   338  }