github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:51</date> 10 //</624342690430980096> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package whisperv6 29 30 import ( 31 "crypto/ecdsa" 32 "fmt" 33 "sync" 34 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/crypto" 37 "github.com/ethereum/go-ethereum/log" 38 ) 39 40 // 41 type Filter struct { 42 Src *ecdsa.PublicKey // 43 KeyAsym *ecdsa.PrivateKey // 44 KeySym []byte // 45 Topics [][]byte // 46 PoW float64 // 47 AllowP2P bool // 48 SymKeyHash common.Hash // 49 id string // 50 51 Messages map[common.Hash]*ReceivedMessage 52 mutex sync.RWMutex 53 } 54 55 // 56 type Filters struct { 57 watchers map[string]*Filter 58 59 topicMatcher map[TopicType]map[*Filter]struct{} // 60 allTopicsMatcher map[*Filter]struct{} // 61 62 whisper *Whisper 63 mutex sync.RWMutex 64 } 65 66 // 67 func NewFilters(w *Whisper) *Filters { 68 return &Filters{ 69 watchers: make(map[string]*Filter), 70 topicMatcher: make(map[TopicType]map[*Filter]struct{}), 71 allTopicsMatcher: make(map[*Filter]struct{}), 72 whisper: w, 73 } 74 } 75 76 // 77 func (fs *Filters) Install(watcher *Filter) (string, error) { 78 if watcher.KeySym != nil && watcher.KeyAsym != nil { 79 return "", fmt.Errorf("filters must choose between symmetric and asymmetric keys") 80 } 81 82 if watcher.Messages == nil { 83 watcher.Messages = make(map[common.Hash]*ReceivedMessage) 84 } 85 86 id, err := GenerateRandomID() 87 if err != nil { 88 return "", err 89 } 90 91 fs.mutex.Lock() 92 defer fs.mutex.Unlock() 93 94 if fs.watchers[id] != nil { 95 return "", fmt.Errorf("failed to generate unique ID") 96 } 97 98 if watcher.expectsSymmetricEncryption() { 99 watcher.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 100 } 101 102 watcher.id = id 103 fs.watchers[id] = watcher 104 fs.addTopicMatcher(watcher) 105 return id, err 106 } 107 108 // 109 // 110 func (fs *Filters) Uninstall(id string) bool { 111 fs.mutex.Lock() 112 defer fs.mutex.Unlock() 113 if fs.watchers[id] != nil { 114 fs.removeFromTopicMatchers(fs.watchers[id]) 115 delete(fs.watchers, id) 116 return true 117 } 118 return false 119 } 120 121 // 122 // 123 // 124 func (fs *Filters) addTopicMatcher(watcher *Filter) { 125 if len(watcher.Topics) == 0 { 126 fs.allTopicsMatcher[watcher] = struct{}{} 127 } else { 128 for _, t := range watcher.Topics { 129 topic := BytesToTopic(t) 130 if fs.topicMatcher[topic] == nil { 131 fs.topicMatcher[topic] = make(map[*Filter]struct{}) 132 } 133 fs.topicMatcher[topic][watcher] = struct{}{} 134 } 135 } 136 } 137 138 // 139 func (fs *Filters) removeFromTopicMatchers(watcher *Filter) { 140 delete(fs.allTopicsMatcher, watcher) 141 for _, topic := range watcher.Topics { 142 delete(fs.topicMatcher[BytesToTopic(topic)], watcher) 143 } 144 } 145 146 // 147 // 148 func (fs *Filters) getWatchersByTopic(topic TopicType) []*Filter { 149 res := make([]*Filter, 0, len(fs.allTopicsMatcher)) 150 for watcher := range fs.allTopicsMatcher { 151 res = append(res, watcher) 152 } 153 for watcher := range fs.topicMatcher[topic] { 154 res = append(res, watcher) 155 } 156 return res 157 } 158 159 // 160 func (fs *Filters) Get(id string) *Filter { 161 fs.mutex.RLock() 162 defer fs.mutex.RUnlock() 163 return fs.watchers[id] 164 } 165 166 // 167 // 168 func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { 169 var msg *ReceivedMessage 170 171 fs.mutex.RLock() 172 defer fs.mutex.RUnlock() 173 174 candidates := fs.getWatchersByTopic(env.Topic) 175 for _, watcher := range candidates { 176 if p2pMessage && !watcher.AllowP2P { 177 log.Trace(fmt.Sprintf("msg [%x], filter [%s]: p2p messages are not allowed", env.Hash(), watcher.id)) 178 continue 179 } 180 181 var match bool 182 if msg != nil { 183 match = watcher.MatchMessage(msg) 184 } else { 185 match = watcher.MatchEnvelope(env) 186 if match { 187 msg = env.Open(watcher) 188 if msg == nil { 189 log.Trace("processing message: failed to open", "message", env.Hash().Hex(), "filter", watcher.id) 190 } 191 } else { 192 log.Trace("processing message: does not match", "message", env.Hash().Hex(), "filter", watcher.id) 193 } 194 } 195 196 if match && msg != nil { 197 log.Trace("processing message: decrypted", "hash", env.Hash().Hex()) 198 if watcher.Src == nil || IsPubKeyEqual(msg.Src, watcher.Src) { 199 watcher.Trigger(msg) 200 } 201 } 202 } 203 } 204 205 func (f *Filter) expectsAsymmetricEncryption() bool { 206 return f.KeyAsym != nil 207 } 208 209 func (f *Filter) expectsSymmetricEncryption() bool { 210 return f.KeySym != nil 211 } 212 213 // 214 // 215 func (f *Filter) Trigger(msg *ReceivedMessage) { 216 f.mutex.Lock() 217 defer f.mutex.Unlock() 218 219 if _, exist := f.Messages[msg.EnvelopeHash]; !exist { 220 f.Messages[msg.EnvelopeHash] = msg 221 } 222 } 223 224 // 225 // 226 func (f *Filter) Retrieve() (all []*ReceivedMessage) { 227 f.mutex.Lock() 228 defer f.mutex.Unlock() 229 230 all = make([]*ReceivedMessage, 0, len(f.Messages)) 231 for _, msg := range f.Messages { 232 all = append(all, msg) 233 } 234 235 f.Messages = make(map[common.Hash]*ReceivedMessage) // 236 return all 237 } 238 239 // 240 // 241 // 242 // 243 func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { 244 if f.PoW > 0 && msg.PoW < f.PoW { 245 return false 246 } 247 248 if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() { 249 return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) 250 } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { 251 return f.SymKeyHash == msg.SymKeyHash 252 } 253 return false 254 } 255 256 // 257 // 258 // 259 // 260 func (f *Filter) MatchEnvelope(envelope *Envelope) bool { 261 return f.PoW <= 0 || envelope.pow >= f.PoW 262 } 263 264 // 265 func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool { 266 if !ValidatePublicKey(a) { 267 return false 268 } else if !ValidatePublicKey(b) { 269 return false 270 } 271 // 272 return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0 273 } 274