github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/keystore/keystore.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:26</date> 10 //</624342585145561088> 11 12 13 //package keystore实现对secp256k1私钥的加密存储。 14 // 15 //根据Web3秘密存储规范,密钥存储为加密的JSON文件。 16 //有关详细信息,请参阅https://github.com/ethereum/wiki/wiki/web3-secret-storage-definition。 17 package keystore 18 19 import ( 20 "crypto/ecdsa" 21 crand "crypto/rand" 22 "errors" 23 "fmt" 24 "math/big" 25 "os" 26 "path/filepath" 27 "reflect" 28 "runtime" 29 "sync" 30 "time" 31 32 "github.com/ethereum/go-ethereum/accounts" 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/crypto" 36 "github.com/ethereum/go-ethereum/event" 37 ) 38 39 var ( 40 ErrLocked = accounts.NewAuthNeededError("password or unlock") 41 ErrNoMatch = errors.New("no key for given address or file") 42 ErrDecrypt = errors.New("could not decrypt key with given passphrase") 43 ) 44 45 //keystore type是keystore后端的反射类型。 46 var KeyStoreType = reflect.TypeOf(&KeyStore{}) 47 48 //keystorescheme是协议方案的前缀帐户和钱包URL。 49 const KeyStoreScheme = "keystore" 50 51 //钱包刷新之间的最长时间(如果文件系统通知不起作用)。 52 const walletRefreshCycle = 3 * time.Second 53 54 //keystore管理磁盘上的密钥存储目录。 55 type KeyStore struct { 56 storage keyStore //存储后端,可能是明文或加密的 57 cache *accountCache //文件系统存储上的内存帐户缓存 58 changes chan struct{} //从缓存接收更改通知的通道 59 unlocked map[common.Address]*unlocked //当前未锁定的帐户(解密的私钥) 60 61 wallets []accounts.Wallet //单个钥匙文件周围的钱包包装纸 62 updateFeed event.Feed //通知钱包添加/删除的事件源 63 updateScope event.SubscriptionScope //订阅范围跟踪当前实时侦听器 64 updating bool //事件通知循环是否正在运行 65 66 mu sync.RWMutex 67 } 68 69 type unlocked struct { 70 *Key 71 abort chan struct{} 72 } 73 74 //newkeystore为给定目录创建一个keystore。 75 func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore { 76 keydir, _ = filepath.Abs(keydir) 77 ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}} 78 ks.init(keydir) 79 return ks 80 } 81 82 //newplaintextkeystore为给定目录创建一个keystore。 83 //已弃用:使用newkeystore。 84 func NewPlaintextKeyStore(keydir string) *KeyStore { 85 keydir, _ = filepath.Abs(keydir) 86 ks := &KeyStore{storage: &keyStorePlain{keydir}} 87 ks.init(keydir) 88 return ks 89 } 90 91 func (ks *KeyStore) init(keydir string) { 92 //锁定互斥体,因为帐户缓存可能使用事件回调 93 ks.mu.Lock() 94 defer ks.mu.Unlock() 95 96 //初始化一组未锁定的密钥和帐户缓存 97 ks.unlocked = make(map[common.Address]*unlocked) 98 ks.cache, ks.changes = newAccountCache(keydir) 99 100 //TODO:要使此终结器工作,必须没有引用 101 //对KS。AddressCache不保留引用,但未锁定的键会保留引用, 102 //因此,在所有定时解锁过期之前,终结器不会触发。 103 runtime.SetFinalizer(ks, func(m *KeyStore) { 104 m.cache.close() 105 }) 106 //从缓存创建钱包的初始列表 107 accs := ks.cache.accounts() 108 ks.wallets = make([]accounts.Wallet, len(accs)) 109 for i := 0; i < len(accs); i++ { 110 ks.wallets[i] = &keystoreWallet{account: accs[i], keystore: ks} 111 } 112 } 113 114 //钱包实现accounts.backend,从 115 //密钥存储目录。 116 func (ks *KeyStore) Wallets() []accounts.Wallet { 117 //确保钱包列表与帐户缓存同步 118 ks.refreshWallets() 119 120 ks.mu.RLock() 121 defer ks.mu.RUnlock() 122 123 cpy := make([]accounts.Wallet, len(ks.wallets)) 124 copy(cpy, ks.wallets) 125 return cpy 126 } 127 128 //刷新钱包检索当前帐户列表,并基于此执行任何操作 129 //必要的钱包更新。 130 func (ks *KeyStore) refreshWallets() { 131 //检索当前帐户列表 132 ks.mu.Lock() 133 accs := ks.cache.accounts() 134 135 //将当前钱包列表转换为新列表 136 wallets := make([]accounts.Wallet, 0, len(accs)) 137 events := []accounts.WalletEvent{} 138 139 for _, account := range accs { 140 //把钱包放在下一个账户前 141 for len(ks.wallets) > 0 && ks.wallets[0].URL().Cmp(account.URL) < 0 { 142 events = append(events, accounts.WalletEvent{Wallet: ks.wallets[0], Kind: accounts.WalletDropped}) 143 ks.wallets = ks.wallets[1:] 144 } 145 //如果没有更多的钱包或帐户在下一个之前,请包装新钱包 146 if len(ks.wallets) == 0 || ks.wallets[0].URL().Cmp(account.URL) > 0 { 147 wallet := &keystoreWallet{account: account, keystore: ks} 148 149 events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived}) 150 wallets = append(wallets, wallet) 151 continue 152 } 153 //如果账户与第一个钱包相同,请保留它 154 if ks.wallets[0].Accounts()[0] == account { 155 wallets = append(wallets, ks.wallets[0]) 156 ks.wallets = ks.wallets[1:] 157 continue 158 } 159 } 160 //扔掉所有剩余的钱包,并设置新的一批 161 for _, wallet := range ks.wallets { 162 events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletDropped}) 163 } 164 ks.wallets = wallets 165 ks.mu.Unlock() 166 167 //启动所有钱包事件并返回 168 for _, event := range events { 169 ks.updateFeed.Send(event) 170 } 171 } 172 173 //subscribe实现accounts.backend,创建对的异步订阅 174 //接收有关添加或删除密钥库钱包的通知。 175 func (ks *KeyStore) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription { 176 //我们需要mutex来可靠地启动/停止更新循环 177 ks.mu.Lock() 178 defer ks.mu.Unlock() 179 180 //订阅调用方并跟踪订阅方计数 181 sub := ks.updateScope.Track(ks.updateFeed.Subscribe(sink)) 182 183 //订阅服务器需要一个活动的通知循环,启动它 184 if !ks.updating { 185 ks.updating = true 186 go ks.updater() 187 } 188 return sub 189 } 190 191 //更新程序负责维护存储在 192 //密钥库,用于启动钱包添加/删除事件。它倾听 193 //来自基础帐户缓存的帐户更改事件,并且还定期 194 //强制手动刷新(仅适用于文件系统通知程序所在的系统 195 //没有运行)。 196 func (ks *KeyStore) updater() { 197 for { 198 //等待帐户更新或刷新超时 199 select { 200 case <-ks.changes: 201 case <-time.After(walletRefreshCycle): 202 } 203 //运行钱包刷新程序 204 ks.refreshWallets() 205 206 //如果我们所有的订户都离开了,请停止更新程序 207 ks.mu.Lock() 208 if ks.updateScope.Count() == 0 { 209 ks.updating = false 210 ks.mu.Unlock() 211 return 212 } 213 ks.mu.Unlock() 214 } 215 } 216 217 //hasAddress报告具有给定地址的密钥是否存在。 218 func (ks *KeyStore) HasAddress(addr common.Address) bool { 219 return ks.cache.hasAddress(addr) 220 } 221 222 //帐户返回目录中存在的所有密钥文件。 223 func (ks *KeyStore) Accounts() []accounts.Account { 224 return ks.cache.accounts() 225 } 226 227 //如果密码短语正确,则delete将删除与帐户匹配的密钥。 228 //如果帐户不包含文件名,则地址必须与唯一键匹配。 229 func (ks *KeyStore) Delete(a accounts.Account, passphrase string) error { 230 //解密密钥不是真正必要的,但我们确实需要 231 //不管怎样,检查密码然后把钥匙调零 232 //紧接着。 233 a, key, err := ks.getDecryptedKey(a, passphrase) 234 if key != nil { 235 zeroKey(key.PrivateKey) 236 } 237 if err != nil { 238 return err 239 } 240 //这里的秩序至关重要。钥匙从 241 //文件消失后缓存,以便在 242 //between不会再将其插入缓存。 243 err = os.Remove(a.URL.Path) 244 if err == nil { 245 ks.cache.delete(a) 246 ks.refreshWallets() 247 } 248 return err 249 } 250 251 //signhash为给定哈希计算ECDSA签名。产生的 252 //签名采用[R S V]格式,其中V为0或1。 253 func (ks *KeyStore) SignHash(a accounts.Account, hash []byte) ([]byte, error) { 254 //查找要签名的密钥,如果找不到,则中止 255 ks.mu.RLock() 256 defer ks.mu.RUnlock() 257 258 unlockedKey, found := ks.unlocked[a.Address] 259 if !found { 260 return nil, ErrLocked 261 } 262 //使用普通ECDSA操作对哈希进行签名 263 return crypto.Sign(hash, unlockedKey.PrivateKey) 264 } 265 266 //signtx用请求的帐户对给定的事务进行签名。 267 func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { 268 //查找要签名的密钥,如果找不到,则中止 269 ks.mu.RLock() 270 defer ks.mu.RUnlock() 271 272 unlockedKey, found := ks.unlocked[a.Address] 273 if !found { 274 return nil, ErrLocked 275 } 276 //根据链ID的存在,用EIP155或宅基地签名 277 if chainID != nil { 278 return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey) 279 } 280 return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey) 281 } 282 283 //如果私钥与给定地址匹配,则signhashwithpassphrase将对哈希进行签名 284 //可以用给定的密码短语解密。生成的签名在 285 //[R_S_V]格式,其中V为0或1。 286 func (ks *KeyStore) SignHashWithPassphrase(a accounts.Account, passphrase string, hash []byte) (signature []byte, err error) { 287 _, key, err := ks.getDecryptedKey(a, passphrase) 288 if err != nil { 289 return nil, err 290 } 291 defer zeroKey(key.PrivateKey) 292 return crypto.Sign(hash, key.PrivateKey) 293 } 294 295 //如果私钥与 296 //给定的地址可以用给定的密码短语解密。 297 func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { 298 _, key, err := ks.getDecryptedKey(a, passphrase) 299 if err != nil { 300 return nil, err 301 } 302 defer zeroKey(key.PrivateKey) 303 304 //根据链ID的存在,用EIP155或宅基地签名 305 if chainID != nil { 306 return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey) 307 } 308 return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey) 309 } 310 311 //解锁无限期地解锁给定的帐户。 312 func (ks *KeyStore) Unlock(a accounts.Account, passphrase string) error { 313 return ks.TimedUnlock(a, passphrase, 0) 314 } 315 316 //lock从内存中删除具有给定地址的私钥。 317 func (ks *KeyStore) Lock(addr common.Address) error { 318 ks.mu.Lock() 319 if unl, found := ks.unlocked[addr]; found { 320 ks.mu.Unlock() 321 ks.expire(addr, unl, time.Duration(0)*time.Nanosecond) 322 } else { 323 ks.mu.Unlock() 324 } 325 return nil 326 } 327 328 //timedunlock使用密码短语解锁给定的帐户。帐户 329 //在超时期间保持解锁状态。超时0将解锁帐户 330 //直到程序退出。帐户必须与唯一的密钥文件匹配。 331 // 332 //如果帐户地址在一段时间内已解锁,则TimedUnlock将扩展或 333 //缩短活动解锁超时。如果地址以前是解锁的 334 //无限期地超时不会改变。 335 func (ks *KeyStore) TimedUnlock(a accounts.Account, passphrase string, timeout time.Duration) error { 336 a, key, err := ks.getDecryptedKey(a, passphrase) 337 if err != nil { 338 return err 339 } 340 341 ks.mu.Lock() 342 defer ks.mu.Unlock() 343 u, found := ks.unlocked[a.Address] 344 if found { 345 if u.abort == nil { 346 //地址被无限期地解锁,所以解锁 347 //超时会让人困惑。 348 zeroKey(key.PrivateKey) 349 return nil 350 } 351 //终止过期的goroutine并在下面替换它。 352 close(u.abort) 353 } 354 if timeout > 0 { 355 u = &unlocked{Key: key, abort: make(chan struct{})} 356 go ks.expire(a.Address, u, timeout) 357 } else { 358 u = &unlocked{Key: key} 359 } 360 ks.unlocked[a.Address] = u 361 return nil 362 } 363 364 //find将给定帐户解析为密钥库中的唯一条目。 365 func (ks *KeyStore) Find(a accounts.Account) (accounts.Account, error) { 366 ks.cache.maybeReload() 367 ks.cache.mu.Lock() 368 a, err := ks.cache.find(a) 369 ks.cache.mu.Unlock() 370 return a, err 371 } 372 373 func (ks *KeyStore) getDecryptedKey(a accounts.Account, auth string) (accounts.Account, *Key, error) { 374 a, err := ks.Find(a) 375 if err != nil { 376 return a, nil, err 377 } 378 key, err := ks.storage.GetKey(a.Address, a.URL.Path, auth) 379 return a, key, err 380 } 381 382 func (ks *KeyStore) expire(addr common.Address, u *unlocked, timeout time.Duration) { 383 t := time.NewTimer(timeout) 384 defer t.Stop() 385 select { 386 case <-u.abort: 387 //刚刚辞职 388 case <-t.C: 389 ks.mu.Lock() 390 //仅当它仍然是DropLater的同一个键实例时才删除 391 //与一起启动。我们可以用指针相等来检查 392 //因为每次键 393 //解锁。 394 if ks.unlocked[addr] == u { 395 zeroKey(u.PrivateKey) 396 delete(ks.unlocked, addr) 397 } 398 ks.mu.Unlock() 399 } 400 } 401 402 //newaccount生成一个新密钥并将其存储到密钥目录中, 403 //用密码短语加密。 404 func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) { 405 _, account, err := storeNewKey(ks.storage, crand.Reader, passphrase) 406 if err != nil { 407 return accounts.Account{}, err 408 } 409 //而是立即将帐户添加到缓存中 410 //而不是等待文件系统通知来接收它。 411 ks.cache.add(account) 412 ks.refreshWallets() 413 return account, nil 414 } 415 416 //以json密钥的形式导出,并用newpassphrase加密。 417 func (ks *KeyStore) Export(a accounts.Account, passphrase, newPassphrase string) (keyJSON []byte, err error) { 418 _, key, err := ks.getDecryptedKey(a, passphrase) 419 if err != nil { 420 return nil, err 421 } 422 var N, P int 423 if store, ok := ks.storage.(*keyStorePassphrase); ok { 424 N, P = store.scryptN, store.scryptP 425 } else { 426 N, P = StandardScryptN, StandardScryptP 427 } 428 return EncryptKey(key, newPassphrase, N, P) 429 } 430 431 //import将给定的加密JSON密钥存储到密钥目录中。 432 func (ks *KeyStore) Import(keyJSON []byte, passphrase, newPassphrase string) (accounts.Account, error) { 433 key, err := DecryptKey(keyJSON, passphrase) 434 if key != nil && key.PrivateKey != nil { 435 defer zeroKey(key.PrivateKey) 436 } 437 if err != nil { 438 return accounts.Account{}, err 439 } 440 return ks.importKey(key, newPassphrase) 441 } 442 443 //importecdsa将给定的密钥存储到密钥目录中,并用密码短语对其进行加密。 444 func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (accounts.Account, error) { 445 key := newKeyFromECDSA(priv) 446 if ks.cache.hasAddress(key.Address) { 447 return accounts.Account{}, fmt.Errorf("account already exists") 448 } 449 return ks.importKey(key, passphrase) 450 } 451 452 func (ks *KeyStore) importKey(key *Key, passphrase string) (accounts.Account, error) { 453 a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.storage.JoinPath(keyFileName(key.Address))}} 454 if err := ks.storage.StoreKey(a.URL.Path, key, passphrase); err != nil { 455 return accounts.Account{}, err 456 } 457 ks.cache.add(a) 458 ks.refreshWallets() 459 return a, nil 460 } 461 462 //更新更改现有帐户的密码。 463 func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string) error { 464 a, key, err := ks.getDecryptedKey(a, passphrase) 465 if err != nil { 466 return err 467 } 468 return ks.storage.StoreKey(a.URL.Path, key, newPassphrase) 469 } 470 471 //importpresalekey解密给定的以太坊预售钱包和商店 472 //密钥目录中的密钥文件。密钥文件使用相同的密码短语加密。 473 func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (accounts.Account, error) { 474 a, _, err := importPreSaleKey(ks.storage, keyJSON, passphrase) 475 if err != nil { 476 return a, err 477 } 478 ks.cache.add(a) 479 ks.refreshWallets() 480 return a, nil 481 } 482 483 //zerokey使内存中的私钥归零。 484 func zeroKey(k *ecdsa.PrivateKey) { 485 b := k.D.Bits() 486 for i := range b { 487 b[i] = 0 488 } 489 } 490