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