github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/usbwallet/hub.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 // 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 package usbwallet 26 27 import ( 28 "errors" 29 "runtime" 30 "sync" 31 "time" 32 33 "github.com/ethereum/go-ethereum/accounts" 34 "github.com/ethereum/go-ethereum/event" 35 "github.com/ethereum/go-ethereum/log" 36 "github.com/karalabe/hid" 37 ) 38 39 //Ledgerscheme是协议方案的前缀帐户和钱包URL。 40 const LedgerScheme = "ledger" 41 42 //Trezorscheme是协议方案的前缀帐户和钱包URL。 43 const TrezorScheme = "trezor" 44 45 //刷新周期是钱包刷新之间的最长时间(如果是USB热插拔 46 //通知不起作用)。 47 const refreshCycle = time.Second 48 49 //RefreshThrottling是钱包刷新之间避免USB的最短时间间隔。 50 //蹂躏 51 const refreshThrottling = 500 * time.Millisecond 52 53 //Hub是一个帐户。后端可以查找和处理通用的USB硬件钱包。 54 type Hub struct { 55 scheme string //协议方案前缀帐户和钱包URL。 56 vendorID uint16 //用于设备发现的USB供应商标识符 57 productIDs []uint16 //用于设备发现的USB产品标识符 58 usageID uint16 //用于MacOS设备发现的USB使用页标识符 59 endpointID int //用于非MacOS设备发现的USB端点标识符 60 makeDriver func(log.Logger) driver //构造供应商特定驱动程序的工厂方法 61 62 refreshed time.Time //上次刷新钱包列表时的时间实例 63 wallets []accounts.Wallet //当前跟踪的USB钱包设备列表 64 updateFeed event.Feed //通知钱包添加/删除的事件源 65 updateScope event.SubscriptionScope //订阅范围跟踪当前实时侦听器 66 updating bool //事件通知循环是否正在运行 67 68 quit chan chan error 69 70 stateLock sync.RWMutex //保护轮毂内部不受滚道的影响 71 72 //TODO(karalabe):如果热插拔落在Windows上,则移除。 73 commsPend int //阻止枚举的操作数 74 commsLock sync.Mutex //保护挂起计数器和枚举的锁 75 } 76 77 //newledgerhub为分类帐设备创建了一个新的硬件钱包管理器。 78 func NewLedgerHub() (*Hub, error) { 79 /*urn newhub(Ledgerscheme,0x2c97,[]uint16 0x0000/*Ledger Blue*/,0x001/*Ledger Nano S*/,0xffa0,0,NewledgerDriver) 80 } 81 82 //newtrezorhub为trezor设备创建新的硬件钱包管理器。 83 func newtrezorhub()(*hub,错误) 84 返回newhub(trezorscheme,0x534c,[]uint16 0x001/*trezor 1*/}, 0xff00, 0, newTrezorDriver) 85 86 } 87 88 //NewHub为通用USB设备创建了一个新的硬件钱包管理器。 89 func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { 90 if !hid.Supported() { 91 return nil, errors.New("unsupported platform") 92 } 93 hub := &Hub{ 94 scheme: scheme, 95 vendorID: vendorID, 96 productIDs: productIDs, 97 usageID: usageID, 98 endpointID: endpointID, 99 makeDriver: makeDriver, 100 quit: make(chan chan error), 101 } 102 hub.refreshWallets() 103 return hub, nil 104 } 105 106 //钱包实现帐户。后端,返回当前跟踪的所有USB 107 //看起来像是硬件钱包的设备。 108 func (hub *Hub) Wallets() []accounts.Wallet { 109 //确保钱包列表是最新的 110 hub.refreshWallets() 111 112 hub.stateLock.RLock() 113 defer hub.stateLock.RUnlock() 114 115 cpy := make([]accounts.Wallet, len(hub.wallets)) 116 copy(cpy, hub.wallets) 117 return cpy 118 } 119 120 //刷新钱包扫描连接到机器的USB设备并更新 121 //基于找到的设备的钱包列表。 122 func (hub *Hub) refreshWallets() { 123 //不要像疯了一样扫描USB,用户会在一个循环中取出钱包。 124 hub.stateLock.RLock() 125 elapsed := time.Since(hub.refreshed) 126 hub.stateLock.RUnlock() 127 128 if elapsed < refreshThrottling { 129 return 130 } 131 //检索USB钱包设备的当前列表 132 var devices []hid.DeviceInfo 133 134 if runtime.GOOS == "linux" { 135 //Linux上的hidapi在枚举期间打开设备以检索一些信息, 136 //如果正在等待用户确认,则破坏分类帐协议。这个 137 //在分类帐上确认了错误,但不会在旧设备上修复,所以我们 138 //需要自己防止并发通信。更优雅的解决方案是 139 //放弃枚举以支持热插拔事件,但这还不起作用 140 //在Windows上,所以如果我们无论如何都需要破解它,现在这就更优雅了。 141 hub.commsLock.Lock() 142 if hub.commsPend > 0 { //正在等待确认,不刷新 143 hub.commsLock.Unlock() 144 return 145 } 146 } 147 for _, info := range hid.Enumerate(hub.vendorID, 0) { 148 for _, id := range hub.productIDs { 149 if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { 150 devices = append(devices, info) 151 break 152 } 153 } 154 } 155 if runtime.GOOS == "linux" { 156 //请参阅枚举前的基本原理,了解为什么只在Linux上需要这样做。 157 hub.commsLock.Unlock() 158 } 159 //将当前钱包列表转换为新列表 160 hub.stateLock.Lock() 161 162 wallets := make([]accounts.Wallet, 0, len(devices)) 163 events := []accounts.WalletEvent{} 164 165 for _, device := range devices { 166 url := accounts.URL{Scheme: hub.scheme, Path: device.Path} 167 168 //将钱包放在下一个设备或因某种原因失败的设备前面 169 for len(hub.wallets) > 0 { 170 //如果我们超过当前设备并找到可操作的设备,则中止 171 _, failure := hub.wallets[0].Status() 172 if hub.wallets[0].URL().Cmp(url) >= 0 || failure == nil { 173 break 174 } 175 //丢弃陈旧和故障的设备 176 events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Kind: accounts.WalletDropped}) 177 hub.wallets = hub.wallets[1:] 178 } 179 //如果没有更多钱包或设备在下一个之前,请包装新钱包。 180 if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 { 181 logger := log.New("url", url) 182 wallet := &wallet{hub: hub, driver: hub.makeDriver(logger), url: &url, info: device, log: logger} 183 184 events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived}) 185 wallets = append(wallets, wallet) 186 continue 187 } 188 //如果设备与第一个钱包相同,请保留它 189 if hub.wallets[0].URL().Cmp(url) == 0 { 190 wallets = append(wallets, hub.wallets[0]) 191 hub.wallets = hub.wallets[1:] 192 continue 193 } 194 } 195 //扔掉所有剩余的钱包,并设置新的一批 196 for _, wallet := range hub.wallets { 197 events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped}) 198 } 199 hub.refreshed = time.Now() 200 hub.wallets = wallets 201 hub.stateLock.Unlock() 202 203 //启动所有钱包事件并返回 204 for _, event := range events { 205 hub.updateFeed.Send(event) 206 } 207 } 208 209 //subscribe实现accounts.backend,创建对的异步订阅 210 //接收有关添加或删除USB钱包的通知。 211 func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { 212 //我们需要mutex来可靠地启动/停止更新循环 213 hub.stateLock.Lock() 214 defer hub.stateLock.Unlock() 215 216 //订阅调用方并跟踪订阅方计数 217 sub := hub.updateScope.Track(hub.updateFeed.Subscribe(sink)) 218 219 //订阅服务器需要一个活动的通知循环,启动它 220 if !hub.updating { 221 hub.updating = true 222 go hub.updater() 223 } 224 return sub 225 } 226 227 //更新程序负责维护管理的钱包的最新列表 228 //通过USB集线器启动钱包添加/删除事件。 229 func (hub *Hub) updater() { 230 for { 231 //TODO:等待USB热插拔事件(尚不支持)或刷新超时 232 //<Hub变化 233 time.Sleep(refreshCycle) 234 235 //运行钱包刷新程序 236 hub.refreshWallets() 237 238 //如果我们所有的订户都离开了,请停止更新程序 239 hub.stateLock.Lock() 240 if hub.updateScope.Count() == 0 { 241 hub.updating = false 242 hub.stateLock.Unlock() 243 return 244 } 245 hub.stateLock.Unlock() 246 } 247 }