github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/whisper/whisperv6/filter.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 19:16:46</date>
    10  //</624450125330124800>
    11  
    12  
    13  package whisperv6
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"fmt"
    18  	"sync"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/log"
    23  )
    24  
    25  //筛选器表示耳语消息筛选器
    26  type Filter struct {
    27  Src        *ecdsa.PublicKey  //邮件的发件人
    28  KeyAsym    *ecdsa.PrivateKey //收件人的私钥
    29  KeySym     []byte            //与主题关联的键
    30  Topics     [][]byte          //筛选邮件的主题
    31  PoW        float64           //耳语规范中所述的工作证明
    32  AllowP2P   bool              //指示此筛选器是否对直接对等消息感兴趣
    33  SymKeyHash common.Hash       //优化所需的对称密钥的keccak256hash
    34  id         string            //唯一标识符
    35  
    36  	Messages map[common.Hash]*ReceivedMessage
    37  	mutex    sync.RWMutex
    38  }
    39  
    40  //筛选器表示筛选器的集合
    41  type Filters struct {
    42  	watchers map[string]*Filter
    43  
    44  topicMatcher     map[TopicType]map[*Filter]struct{} //将主题映射到在消息与该主题匹配时感兴趣收到通知的筛选器
    45  allTopicsMatcher map[*Filter]struct{}               //列出将通知新邮件的所有筛选器,无论其主题是什么
    46  
    47  	whisper *Whisper
    48  	mutex   sync.RWMutex
    49  }
    50  
    51  //newfilters返回新创建的筛选器集合
    52  func NewFilters(w *Whisper) *Filters {
    53  	return &Filters{
    54  		watchers:         make(map[string]*Filter),
    55  		topicMatcher:     make(map[TopicType]map[*Filter]struct{}),
    56  		allTopicsMatcher: make(map[*Filter]struct{}),
    57  		whisper:          w,
    58  	}
    59  }
    60  
    61  //安装将向筛选器集合添加新筛选器
    62  func (fs *Filters) Install(watcher *Filter) (string, error) {
    63  	if watcher.KeySym != nil && watcher.KeyAsym != nil {
    64  		return "", fmt.Errorf("filters must choose between symmetric and asymmetric keys")
    65  	}
    66  
    67  	if watcher.Messages == nil {
    68  		watcher.Messages = make(map[common.Hash]*ReceivedMessage)
    69  	}
    70  
    71  	id, err := GenerateRandomID()
    72  	if err != nil {
    73  		return "", err
    74  	}
    75  
    76  	fs.mutex.Lock()
    77  	defer fs.mutex.Unlock()
    78  
    79  	if fs.watchers[id] != nil {
    80  		return "", fmt.Errorf("failed to generate unique ID")
    81  	}
    82  
    83  	if watcher.expectsSymmetricEncryption() {
    84  		watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym)
    85  	}
    86  
    87  	watcher.id = id
    88  	fs.watchers[id] = watcher
    89  	fs.addTopicMatcher(watcher)
    90  	return id, err
    91  }
    92  
    93  //卸载将删除已从中指定ID的筛选器
    94  //筛选器集合
    95  func (fs *Filters) Uninstall(id string) bool {
    96  	fs.mutex.Lock()
    97  	defer fs.mutex.Unlock()
    98  	if fs.watchers[id] != nil {
    99  		fs.removeFromTopicMatchers(fs.watchers[id])
   100  		delete(fs.watchers, id)
   101  		return true
   102  	}
   103  	return false
   104  }
   105  
   106  //addTopicMatcher向主题匹配器添加一个筛选器。
   107  //如果过滤器的主题数组为空,将对每个主题进行尝试。
   108  //否则,将在指定的主题上进行尝试。
   109  func (fs *Filters) addTopicMatcher(watcher *Filter) {
   110  	if len(watcher.Topics) == 0 {
   111  		fs.allTopicsMatcher[watcher] = struct{}{}
   112  	} else {
   113  		for _, t := range watcher.Topics {
   114  			topic := BytesToTopic(t)
   115  			if fs.topicMatcher[topic] == nil {
   116  				fs.topicMatcher[topic] = make(map[*Filter]struct{})
   117  			}
   118  			fs.topicMatcher[topic][watcher] = struct{}{}
   119  		}
   120  	}
   121  }
   122  
   123  //removeFromTopicMatchers从主题匹配器中删除筛选器
   124  func (fs *Filters) removeFromTopicMatchers(watcher *Filter) {
   125  	delete(fs.allTopicsMatcher, watcher)
   126  	for _, topic := range watcher.Topics {
   127  		delete(fs.topicMatcher[BytesToTopic(topic)], watcher)
   128  	}
   129  }
   130  
   131  //GetWatchersByTopic返回一个包含以下筛选器的切片:
   132  //匹配特定主题
   133  func (fs *Filters) getWatchersByTopic(topic TopicType) []*Filter {
   134  	res := make([]*Filter, 0, len(fs.allTopicsMatcher))
   135  	for watcher := range fs.allTopicsMatcher {
   136  		res = append(res, watcher)
   137  	}
   138  	for watcher := range fs.topicMatcher[topic] {
   139  		res = append(res, watcher)
   140  	}
   141  	return res
   142  }
   143  
   144  //get返回集合中具有特定ID的筛选器
   145  func (fs *Filters) Get(id string) *Filter {
   146  	fs.mutex.RLock()
   147  	defer fs.mutex.RUnlock()
   148  	return fs.watchers[id]
   149  }
   150  
   151  //通知观察程序通知已声明感兴趣的任何筛选器
   152  //信封主题。
   153  func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
   154  	var msg *ReceivedMessage
   155  
   156  	fs.mutex.RLock()
   157  	defer fs.mutex.RUnlock()
   158  
   159  	candidates := fs.getWatchersByTopic(env.Topic)
   160  	for _, watcher := range candidates {
   161  		if p2pMessage && !watcher.AllowP2P {
   162  			log.Trace(fmt.Sprintf("msg [%x], filter [%s]: p2p messages are not allowed", env.Hash(), watcher.id))
   163  			continue
   164  		}
   165  
   166  		var match bool
   167  		if msg != nil {
   168  			match = watcher.MatchMessage(msg)
   169  		} else {
   170  			match = watcher.MatchEnvelope(env)
   171  			if match {
   172  				msg = env.Open(watcher)
   173  				if msg == nil {
   174  					log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", watcher.id)
   175  				}
   176  			} else {
   177  				log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", watcher.id)
   178  			}
   179  		}
   180  
   181  		if match && msg != nil {
   182  			log.Trace("processing message: decrypted", "hash", env.Hash().Hex())
   183  			if watcher.Src == nil || IsPubKeyEqual(msg.Src, watcher.Src) {
   184  				watcher.Trigger(msg)
   185  			}
   186  		}
   187  	}
   188  }
   189  
   190  func (f *Filter) expectsAsymmetricEncryption() bool {
   191  	return f.KeyAsym != nil
   192  }
   193  
   194  func (f *Filter) expectsSymmetricEncryption() bool {
   195  	return f.KeySym != nil
   196  }
   197  
   198  //触发器将未知消息添加到筛选器的列表中
   199  //收到的消息。
   200  func (f *Filter) Trigger(msg *ReceivedMessage) {
   201  	f.mutex.Lock()
   202  	defer f.mutex.Unlock()
   203  
   204  	if _, exist := f.Messages[msg.EnvelopeHash]; !exist {
   205  		f.Messages[msg.EnvelopeHash] = msg
   206  	}
   207  }
   208  
   209  //检索将返回所有相关联的已接收消息的列表
   210  //过滤器。
   211  func (f *Filter) Retrieve() (all []*ReceivedMessage) {
   212  	f.mutex.Lock()
   213  	defer f.mutex.Unlock()
   214  
   215  	all = make([]*ReceivedMessage, 0, len(f.Messages))
   216  	for _, msg := range f.Messages {
   217  		all = append(all, msg)
   218  	}
   219  
   220  f.Messages = make(map[common.Hash]*ReceivedMessage) //删除旧邮件
   221  	return all
   222  }
   223  
   224  //MatchMessage检查筛选器是否匹配已解密的
   225  //消息(即已经由
   226  //匹配前一个筛选器选中的信封)。
   227  //这里不检查主题,因为这是由主题匹配器完成的。
   228  func (f *Filter) MatchMessage(msg *ReceivedMessage) bool {
   229  	if f.PoW > 0 && msg.PoW < f.PoW {
   230  		return false
   231  	}
   232  
   233  	if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
   234  		return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst)
   235  	} else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
   236  		return f.SymKeyHash == msg.SymKeyHash
   237  	}
   238  	return false
   239  }
   240  
   241  //匹配信封检查是否值得解密消息。如果
   242  //它返回“true”,要求客户端代码尝试解密
   243  //然后调用matchmessage。
   244  //这里不检查主题,因为这是由主题匹配器完成的。
   245  func (f *Filter) MatchEnvelope(envelope *Envelope) bool {
   246  	return f.PoW <= 0 || envelope.pow >= f.PoW
   247  }
   248  
   249  //isubkeyEqual检查两个公钥是否相等
   250  func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
   251  	if !ValidatePublicKey(a) {
   252  		return false
   253  	} else if !ValidatePublicKey(b) {
   254  		return false
   255  	}
   256  //曲线总是一样的,只要比较点
   257  	return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
   258  }
   259