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 }