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] = &notifier{
   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