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 }