github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/account_cache.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  package keystore
    26  
    27  import (
    28  	"bufio"
    29  	"encoding/json"
    30  	"fmt"
    31  	"os"
    32  	"path/filepath"
    33  	"sort"
    34  	"strings"
    35  	"sync"
    36  	"time"
    37  
    38  	mapset "github.com/deckarep/golang-set"
    39  	"github.com/ethereum/go-ethereum/accounts"
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"github.com/ethereum/go-ethereum/log"
    42  )
    43  
    44  //缓存重新加载之间的最短时间间隔。此限制适用于平台
    45  //不支持更改通知。如果keystore目录没有
    46  //尽管存在,代码最多也会尝试创建一个观察程序。
    47  const minReloadInterval = 2 * time.Second
    48  
    49  type accountsByURL []accounts.Account
    50  
    51  func (s accountsByURL) Len() int           { return len(s) }
    52  func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 }
    53  func (s accountsByURL) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    54  
    55  //尝试解锁时返回ambiguousaddrror
    56  //存在多个文件的地址。
    57  type AmbiguousAddrError struct {
    58  	Addr    common.Address
    59  	Matches []accounts.Account
    60  }
    61  
    62  func (err *AmbiguousAddrError) Error() string {
    63  	files := ""
    64  	for i, a := range err.Matches {
    65  		files += a.URL.Path
    66  		if i < len(err.Matches)-1 {
    67  			files += ", "
    68  		}
    69  	}
    70  	return fmt.Sprintf("multiple keys match address (%s)", files)
    71  }
    72  
    73  //accountcache是密钥库中所有帐户的实时索引。
    74  type accountCache struct {
    75  	keydir   string
    76  	watcher  *watcher
    77  	mu       sync.Mutex
    78  	all      accountsByURL
    79  	byAddr   map[common.Address][]accounts.Account
    80  	throttle *time.Timer
    81  	notify   chan struct{}
    82  	fileC    fileCache
    83  }
    84  
    85  func newAccountCache(keydir string) (*accountCache, chan struct{}) {
    86  	ac := &accountCache{
    87  		keydir: keydir,
    88  		byAddr: make(map[common.Address][]accounts.Account),
    89  		notify: make(chan struct{}, 1),
    90  		fileC:  fileCache{all: mapset.NewThreadUnsafeSet()},
    91  	}
    92  	ac.watcher = newWatcher(ac)
    93  	return ac, ac.notify
    94  }
    95  
    96  func (ac *accountCache) accounts() []accounts.Account {
    97  	ac.maybeReload()
    98  	ac.mu.Lock()
    99  	defer ac.mu.Unlock()
   100  	cpy := make([]accounts.Account, len(ac.all))
   101  	copy(cpy, ac.all)
   102  	return cpy
   103  }
   104  
   105  func (ac *accountCache) hasAddress(addr common.Address) bool {
   106  	ac.maybeReload()
   107  	ac.mu.Lock()
   108  	defer ac.mu.Unlock()
   109  	return len(ac.byAddr[addr]) > 0
   110  }
   111  
   112  func (ac *accountCache) add(newAccount accounts.Account) {
   113  	ac.mu.Lock()
   114  	defer ac.mu.Unlock()
   115  
   116  	i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Cmp(newAccount.URL) >= 0 })
   117  	if i < len(ac.all) && ac.all[i] == newAccount {
   118  		return
   119  	}
   120  //NewAccount不在缓存中。
   121  	ac.all = append(ac.all, accounts.Account{})
   122  	copy(ac.all[i+1:], ac.all[i:])
   123  	ac.all[i] = newAccount
   124  	ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount)
   125  }
   126  
   127  //注意:删除的文件必须是唯一的(即必须同时设置文件和地址)。
   128  func (ac *accountCache) delete(removed accounts.Account) {
   129  	ac.mu.Lock()
   130  	defer ac.mu.Unlock()
   131  
   132  	ac.all = removeAccount(ac.all, removed)
   133  	if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
   134  		delete(ac.byAddr, removed.Address)
   135  	} else {
   136  		ac.byAddr[removed.Address] = ba
   137  	}
   138  }
   139  
   140  //DeleteByFile删除由给定路径引用的帐户。
   141  func (ac *accountCache) deleteByFile(path string) {
   142  	ac.mu.Lock()
   143  	defer ac.mu.Unlock()
   144  	i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Path >= path })
   145  
   146  	if i < len(ac.all) && ac.all[i].URL.Path == path {
   147  		removed := ac.all[i]
   148  		ac.all = append(ac.all[:i], ac.all[i+1:]...)
   149  		if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 {
   150  			delete(ac.byAddr, removed.Address)
   151  		} else {
   152  			ac.byAddr[removed.Address] = ba
   153  		}
   154  	}
   155  }
   156  
   157  func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.Account {
   158  	for i := range slice {
   159  		if slice[i] == elem {
   160  			return append(slice[:i], slice[i+1:]...)
   161  		}
   162  	}
   163  	return slice
   164  }
   165  
   166  //如果存在唯一匹配项,find返回地址的缓存帐户。
   167  //accounts.account的文档解释了精确的匹配规则。
   168  //呼叫者必须持有AC.MU。
   169  func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) {
   170  //如果可能的话,限制搜索以满足候选人的要求。
   171  	matches := ac.all
   172  	if (a.Address != common.Address{}) {
   173  		matches = ac.byAddr[a.Address]
   174  	}
   175  	if a.URL.Path != "" {
   176  //如果只指定了basename,请完成路径。
   177  		if !strings.ContainsRune(a.URL.Path, filepath.Separator) {
   178  			a.URL.Path = filepath.Join(ac.keydir, a.URL.Path)
   179  		}
   180  		for i := range matches {
   181  			if matches[i].URL == a.URL {
   182  				return matches[i], nil
   183  			}
   184  		}
   185  		if (a.Address == common.Address{}) {
   186  			return accounts.Account{}, ErrNoMatch
   187  		}
   188  	}
   189  	switch len(matches) {
   190  	case 1:
   191  		return matches[0], nil
   192  	case 0:
   193  		return accounts.Account{}, ErrNoMatch
   194  	default:
   195  		err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))}
   196  		copy(err.Matches, matches)
   197  		sort.Sort(accountsByURL(err.Matches))
   198  		return accounts.Account{}, err
   199  	}
   200  }
   201  
   202  func (ac *accountCache) maybeReload() {
   203  	ac.mu.Lock()
   204  
   205  	if ac.watcher.running {
   206  		ac.mu.Unlock()
   207  return //观察程序正在运行并将保持缓存的最新状态。
   208  	}
   209  	if ac.throttle == nil {
   210  		ac.throttle = time.NewTimer(0)
   211  	} else {
   212  		select {
   213  		case <-ac.throttle.C:
   214  		default:
   215  			ac.mu.Unlock()
   216  return //缓存最近被重新加载。
   217  		}
   218  	}
   219  //没有观察者在运行,启动它。
   220  	ac.watcher.start()
   221  	ac.throttle.Reset(minReloadInterval)
   222  	ac.mu.Unlock()
   223  	ac.scanAccounts()
   224  }
   225  
   226  func (ac *accountCache) close() {
   227  	ac.mu.Lock()
   228  	ac.watcher.close()
   229  	if ac.throttle != nil {
   230  		ac.throttle.Stop()
   231  	}
   232  	if ac.notify != nil {
   233  		close(ac.notify)
   234  		ac.notify = nil
   235  	}
   236  	ac.mu.Unlock()
   237  }
   238  
   239  //scanaccounts检查文件系统是否发生任何更改,以及
   240  //相应地更新帐户缓存
   241  func (ac *accountCache) scanAccounts() error {
   242  //扫描整个文件夹元数据以查找文件更改
   243  	creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
   244  	if err != nil {
   245  		log.Debug("Failed to reload keystore contents", "err", err)
   246  		return err
   247  	}
   248  	if creates.Cardinality() == 0 && deletes.Cardinality() == 0 && updates.Cardinality() == 0 {
   249  		return nil
   250  	}
   251  //创建一个助手方法来扫描密钥文件的内容
   252  	var (
   253  		buf = new(bufio.Reader)
   254  		key struct {
   255  			Address string `json:"address"`
   256  		}
   257  	)
   258  	readAccount := func(path string) *accounts.Account {
   259  		fd, err := os.Open(path)
   260  		if err != nil {
   261  			log.Trace("Failed to open keystore file", "path", path, "err", err)
   262  			return nil
   263  		}
   264  		defer fd.Close()
   265  		buf.Reset(fd)
   266  //分析地址。
   267  		key.Address = ""
   268  		err = json.NewDecoder(buf).Decode(&key)
   269  		addr := common.HexToAddress(key.Address)
   270  		switch {
   271  		case err != nil:
   272  			log.Debug("Failed to decode keystore key", "path", path, "err", err)
   273  		case (addr == common.Address{}):
   274  			log.Debug("Failed to decode keystore key", "path", path, "err", "missing or zero address")
   275  		default:
   276  			return &accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}}
   277  		}
   278  		return nil
   279  	}
   280  //处理所有文件差异
   281  	start := time.Now()
   282  
   283  	for _, p := range creates.ToSlice() {
   284  		if a := readAccount(p.(string)); a != nil {
   285  			ac.add(*a)
   286  		}
   287  	}
   288  	for _, p := range deletes.ToSlice() {
   289  		ac.deleteByFile(p.(string))
   290  	}
   291  	for _, p := range updates.ToSlice() {
   292  		path := p.(string)
   293  		ac.deleteByFile(path)
   294  		if a := readAccount(path); a != nil {
   295  			ac.add(*a)
   296  		}
   297  	}
   298  	end := time.Now()
   299  
   300  	select {
   301  	case ac.notify <- struct{}{}:
   302  	default:
   303  	}
   304  	log.Trace("Handled keystore changes", "time", end.Sub(start))
   305  	return nil
   306  }