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