github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/pss/notify/notify.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:48</date> 10 //</624342677747404800> 11 12 package notify 13 14 import ( 15 "crypto/ecdsa" 16 "fmt" 17 "sync" 18 19 "github.com/ethereum/go-ethereum/common/hexutil" 20 "github.com/ethereum/go-ethereum/crypto" 21 "github.com/ethereum/go-ethereum/p2p" 22 "github.com/ethereum/go-ethereum/rlp" 23 "github.com/ethereum/go-ethereum/swarm/log" 24 "github.com/ethereum/go-ethereum/swarm/pss" 25 ) 26 27 const ( 28 // 29 MsgCodeStart = iota 30 31 // 32 MsgCodeNotifyWithKey 33 34 // 35 MsgCodeNotify 36 37 // 38 MsgCodeStop 39 MsgCodeMax 40 ) 41 42 const ( 43 DefaultAddressLength = 1 44 symKeyLength = 32 // 45 ) 46 47 var ( 48 // 49 controlTopic = pss.Topic{0x00, 0x00, 0x00, 0x01} 50 ) 51 52 // 53 // 54 // 55 // 56 type Msg struct { 57 Code byte 58 Name []byte 59 Payload []byte 60 namestring string 61 } 62 63 // 64 func NewMsg(code byte, name string, payload []byte) *Msg { 65 return &Msg{ 66 Code: code, 67 Name: []byte(name), 68 Payload: payload, 69 namestring: name, 70 } 71 } 72 73 // 74 func NewMsgFromPayload(payload []byte) (*Msg, error) { 75 msg := &Msg{} 76 err := rlp.DecodeBytes(payload, msg) 77 if err != nil { 78 return nil, err 79 } 80 msg.namestring = string(msg.Name) 81 return msg, nil 82 } 83 84 // 85 type sendBin struct { 86 address pss.PssAddress 87 symKeyId string 88 count int 89 } 90 91 // 92 // 93 type notifier struct { 94 bins map[string]*sendBin 95 topic pss.Topic // 96 threshold int // 97 updateC <-chan []byte 98 quitC chan struct{} 99 } 100 101 func (n *notifier) removeSubscription() { 102 n.quitC <- struct{}{} 103 } 104 105 // 106 type subscription struct { 107 pubkeyId string 108 address pss.PssAddress 109 handler func(string, []byte) error 110 } 111 112 // 113 type Controller struct { 114 pss *pss.Pss 115 notifiers map[string]*notifier 116 subscriptions map[string]*subscription 117 mu sync.Mutex 118 } 119 120 // 121 func NewController(ps *pss.Pss) *Controller { 122 ctrl := &Controller{ 123 pss: ps, 124 notifiers: make(map[string]*notifier), 125 subscriptions: make(map[string]*subscription), 126 } 127 ctrl.pss.Register(&controlTopic, ctrl.Handler) 128 return ctrl 129 } 130 131 // 132 // 133 func (c *Controller) IsActive(name string) bool { 134 c.mu.Lock() 135 defer c.mu.Unlock() 136 return c.isActive(name) 137 } 138 139 func (c *Controller) isActive(name string) bool { 140 _, ok := c.notifiers[name] 141 return ok 142 } 143 144 // 145 // 146 // 147 // 148 func (c *Controller) Subscribe(name string, pubkey *ecdsa.PublicKey, address pss.PssAddress, handler func(string, []byte) error) error { 149 c.mu.Lock() 150 defer c.mu.Unlock() 151 msg := NewMsg(MsgCodeStart, name, c.pss.BaseAddr()) 152 c.pss.SetPeerPublicKey(pubkey, controlTopic, &address) 153 pubkeyId := hexutil.Encode(crypto.FromECDSAPub(pubkey)) 154 smsg, err := rlp.EncodeToBytes(msg) 155 if err != nil { 156 return err 157 } 158 err = c.pss.SendAsym(pubkeyId, controlTopic, smsg) 159 if err != nil { 160 return err 161 } 162 c.subscriptions[name] = &subscription{ 163 pubkeyId: pubkeyId, 164 address: address, 165 handler: handler, 166 } 167 return nil 168 } 169 170 // 171 // 172 func (c *Controller) Unsubscribe(name string) error { 173 c.mu.Lock() 174 defer c.mu.Unlock() 175 sub, ok := c.subscriptions[name] 176 if !ok { 177 return fmt.Errorf("Unknown subscription '%s'", name) 178 } 179 msg := NewMsg(MsgCodeStop, name, sub.address) 180 smsg, err := rlp.EncodeToBytes(msg) 181 if err != nil { 182 return err 183 } 184 err = c.pss.SendAsym(sub.pubkeyId, controlTopic, smsg) 185 if err != nil { 186 return err 187 } 188 delete(c.subscriptions, name) 189 return nil 190 } 191 192 // 193 // 194 // 195 // 196 // 197 func (c *Controller) NewNotifier(name string, threshold int, updateC <-chan []byte) (func(), error) { 198 c.mu.Lock() 199 if c.isActive(name) { 200 c.mu.Unlock() 201 return nil, fmt.Errorf("Notification service %s already exists in controller", name) 202 } 203 quitC := make(chan struct{}) 204 c.notifiers[name] = ¬ifier{ 205 bins: make(map[string]*sendBin), 206 topic: pss.BytesToTopic([]byte(name)), 207 threshold: threshold, 208 updateC: updateC, 209 quitC: quitC, 210 // 211 } 212 c.mu.Unlock() 213 go func() { 214 for { 215 select { 216 case <-quitC: 217 return 218 case data := <-updateC: 219 c.notify(name, data) 220 } 221 } 222 }() 223 224 return c.notifiers[name].removeSubscription, nil 225 } 226 227 // 228 // 229 func (c *Controller) RemoveNotifier(name string) error { 230 c.mu.Lock() 231 defer c.mu.Unlock() 232 currentNotifier, ok := c.notifiers[name] 233 if !ok { 234 return fmt.Errorf("Unknown notification service %s", name) 235 } 236 currentNotifier.removeSubscription() 237 delete(c.notifiers, name) 238 return nil 239 } 240 241 // 242 // 243 // 244 // 245 func (c *Controller) notify(name string, data []byte) error { 246 c.mu.Lock() 247 defer c.mu.Unlock() 248 if !c.isActive(name) { 249 return fmt.Errorf("Notification service %s doesn't exist", name) 250 } 251 msg := NewMsg(MsgCodeNotify, name, data) 252 smsg, err := rlp.EncodeToBytes(msg) 253 if err != nil { 254 return err 255 } 256 for _, m := range c.notifiers[name].bins { 257 log.Debug("sending pss notify", "name", name, "addr", fmt.Sprintf("%x", m.address), "topic", fmt.Sprintf("%x", c.notifiers[name].topic), "data", data) 258 go func(m *sendBin) { 259 err = c.pss.SendSym(m.symKeyId, c.notifiers[name].topic, smsg) 260 if err != nil { 261 log.Warn("Failed to send notify to addr %x: %v", m.address, err) 262 } 263 }(m) 264 } 265 return nil 266 } 267 268 // 269 // 270 // 271 func (c *Controller) addToBin(ntfr *notifier, address []byte) (symKeyId string, pssAddress pss.PssAddress, err error) { 272 273 // 274 if len(address) > ntfr.threshold { 275 address = address[:ntfr.threshold] 276 } 277 278 pssAddress = pss.PssAddress(address) 279 hexAddress := fmt.Sprintf("%x", address) 280 currentBin, ok := ntfr.bins[hexAddress] 281 if ok { 282 currentBin.count++ 283 symKeyId = currentBin.symKeyId 284 } else { 285 symKeyId, err = c.pss.GenerateSymmetricKey(ntfr.topic, &pssAddress, false) 286 if err != nil { 287 return "", nil, err 288 } 289 ntfr.bins[hexAddress] = &sendBin{ 290 address: address, 291 symKeyId: symKeyId, 292 count: 1, 293 } 294 } 295 return symKeyId, pssAddress, nil 296 } 297 298 func (c *Controller) handleStartMsg(msg *Msg, keyid string) (err error) { 299 300 keyidbytes, err := hexutil.Decode(keyid) 301 if err != nil { 302 return err 303 } 304 pubkey, err := crypto.UnmarshalPubkey(keyidbytes) 305 if err != nil { 306 return err 307 } 308 309 // 310 currentNotifier, ok := c.notifiers[msg.namestring] 311 if !ok { 312 return fmt.Errorf("Subscribe attempted on unknown resource '%s'", msg.namestring) 313 } 314 315 // 316 symKeyId, pssAddress, err := c.addToBin(currentNotifier, msg.Payload) 317 if err != nil { 318 return err 319 } 320 321 // 322 symkey, err := c.pss.GetSymmetricKey(symKeyId) 323 if err != nil { 324 return err 325 } 326 err = c.pss.SetPeerPublicKey(pubkey, controlTopic, &pssAddress) 327 if err != nil { 328 return err 329 } 330 331 // 332 notify := []byte{} 333 replyMsg := NewMsg(MsgCodeNotifyWithKey, msg.namestring, make([]byte, len(notify)+symKeyLength)) 334 copy(replyMsg.Payload, notify) 335 copy(replyMsg.Payload[len(notify):], symkey) 336 sReplyMsg, err := rlp.EncodeToBytes(replyMsg) 337 if err != nil { 338 return err 339 } 340 return c.pss.SendAsym(keyid, controlTopic, sReplyMsg) 341 } 342 343 func (c *Controller) handleNotifyWithKeyMsg(msg *Msg) error { 344 symkey := msg.Payload[len(msg.Payload)-symKeyLength:] 345 topic := pss.BytesToTopic(msg.Name) 346 347 // 348 updaterAddr := pss.PssAddress([]byte{}) 349 c.pss.SetSymmetricKey(symkey, topic, &updaterAddr, true) 350 c.pss.Register(&topic, c.Handler) 351 return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload[:len(msg.Payload)-symKeyLength]) 352 } 353 354 func (c *Controller) handleStopMsg(msg *Msg) error { 355 // 356 currentNotifier, ok := c.notifiers[msg.namestring] 357 if !ok { 358 return fmt.Errorf("Unsubscribe attempted on unknown resource '%s'", msg.namestring) 359 } 360 361 // 362 address := msg.Payload 363 if len(msg.Payload) > currentNotifier.threshold { 364 address = address[:currentNotifier.threshold] 365 } 366 367 // 368 hexAddress := fmt.Sprintf("%x", address) 369 currentBin, ok := currentNotifier.bins[hexAddress] 370 if !ok { 371 return fmt.Errorf("found no active bin for address %s", hexAddress) 372 } 373 currentBin.count-- 374 if currentBin.count == 0 { // 375 delete(currentNotifier.bins, hexAddress) 376 } 377 return nil 378 } 379 380 // 381 // 382 func (c *Controller) Handler(smsg []byte, p *p2p.Peer, asymmetric bool, keyid string) error { 383 c.mu.Lock() 384 defer c.mu.Unlock() 385 log.Debug("notify controller handler", "keyid", keyid) 386 387 // 388 msg, err := NewMsgFromPayload(smsg) 389 if err != nil { 390 return err 391 } 392 393 switch msg.Code { 394 case MsgCodeStart: 395 return c.handleStartMsg(msg, keyid) 396 case MsgCodeNotifyWithKey: 397 return c.handleNotifyWithKeyMsg(msg) 398 case MsgCodeNotify: 399 return c.subscriptions[msg.namestring].handler(msg.namestring, msg.Payload) 400 case MsgCodeStop: 401 return c.handleStopMsg(msg) 402 } 403 404 return fmt.Errorf("Invalid message code: %d", msg.Code) 405 } 406