github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/whisper/whisperv5/filter.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package whisperv5
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"sync"
    22  
    23  	"github.com/atheioschain/go-atheios/common"
    24  	"github.com/atheioschain/go-atheios/logger"
    25  	"github.com/atheioschain/go-atheios/logger/glog"
    26  )
    27  
    28  type Filter struct {
    29  	Src        *ecdsa.PublicKey  // Sender of the message
    30  	KeyAsym    *ecdsa.PrivateKey // Private Key of recipient
    31  	KeySym     []byte            // Key associated with the Topic
    32  	Topics     []TopicType       // Topics to filter messages with
    33  	PoW        float64           // Proof of work as described in the Whisper spec
    34  	AcceptP2P  bool              // Indicates whether this filter is interested in direct peer-to-peer messages
    35  	SymKeyHash common.Hash       // The Keccak256Hash of the symmetric key, needed for optimization
    36  
    37  	Messages map[common.Hash]*ReceivedMessage
    38  	mutex    sync.RWMutex
    39  }
    40  
    41  type Filters struct {
    42  	id       uint32 // can contain any value except zero
    43  	watchers map[uint32]*Filter
    44  	whisper  *Whisper
    45  	mutex    sync.RWMutex
    46  }
    47  
    48  func NewFilters(w *Whisper) *Filters {
    49  	return &Filters{
    50  		watchers: make(map[uint32]*Filter),
    51  		whisper:  w,
    52  	}
    53  }
    54  
    55  func (fs *Filters) Install(watcher *Filter) uint32 {
    56  	if watcher.Messages == nil {
    57  		watcher.Messages = make(map[common.Hash]*ReceivedMessage)
    58  	}
    59  
    60  	fs.mutex.Lock()
    61  	defer fs.mutex.Unlock()
    62  
    63  	fs.id++
    64  	fs.watchers[fs.id] = watcher
    65  	return fs.id
    66  }
    67  
    68  func (fs *Filters) Uninstall(id uint32) {
    69  	fs.mutex.Lock()
    70  	defer fs.mutex.Unlock()
    71  	delete(fs.watchers, id)
    72  }
    73  
    74  func (fs *Filters) Get(i uint32) *Filter {
    75  	fs.mutex.RLock()
    76  	defer fs.mutex.RUnlock()
    77  	return fs.watchers[i]
    78  }
    79  
    80  func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) {
    81  	fs.mutex.RLock()
    82  	var msg *ReceivedMessage
    83  	for j, watcher := range fs.watchers {
    84  		if p2pMessage && !watcher.AcceptP2P {
    85  			glog.V(logger.Detail).Infof("msg [%x], filter [%d]: p2p messages are not allowed \n", env.Hash(), j)
    86  			continue
    87  		}
    88  
    89  		var match bool
    90  		if msg != nil {
    91  			match = watcher.MatchMessage(msg)
    92  		} else {
    93  			match = watcher.MatchEnvelope(env)
    94  			if match {
    95  				msg = env.Open(watcher)
    96  				if msg == nil {
    97  					glog.V(logger.Detail).Infof("msg [%x], filter [%d]: failed to open \n", env.Hash(), j)
    98  				}
    99  			} else {
   100  				glog.V(logger.Detail).Infof("msg [%x], filter [%d]: does not match \n", env.Hash(), j)
   101  			}
   102  		}
   103  
   104  		if match && msg != nil {
   105  			watcher.Trigger(msg)
   106  		}
   107  	}
   108  	fs.mutex.RUnlock() // we need to unlock before calling addDecryptedMessage
   109  
   110  	if msg != nil {
   111  		fs.whisper.addDecryptedMessage(msg)
   112  	}
   113  }
   114  
   115  func (f *Filter) expectsAsymmetricEncryption() bool {
   116  	return f.KeyAsym != nil
   117  }
   118  
   119  func (f *Filter) expectsSymmetricEncryption() bool {
   120  	return f.KeySym != nil
   121  }
   122  
   123  func (f *Filter) Trigger(msg *ReceivedMessage) {
   124  	f.mutex.Lock()
   125  	defer f.mutex.Unlock()
   126  
   127  	if _, exist := f.Messages[msg.EnvelopeHash]; !exist {
   128  		f.Messages[msg.EnvelopeHash] = msg
   129  	}
   130  }
   131  
   132  func (f *Filter) Retrieve() (all []*ReceivedMessage) {
   133  	f.mutex.Lock()
   134  	defer f.mutex.Unlock()
   135  
   136  	all = make([]*ReceivedMessage, 0, len(f.Messages))
   137  	for _, msg := range f.Messages {
   138  		all = append(all, msg)
   139  	}
   140  	f.Messages = make(map[common.Hash]*ReceivedMessage) // delete old messages
   141  	return all
   142  }
   143  
   144  func (f *Filter) MatchMessage(msg *ReceivedMessage) bool {
   145  	if f.PoW > 0 && msg.PoW < f.PoW {
   146  		return false
   147  	}
   148  	if f.Src != nil && !IsPubKeyEqual(msg.Src, f.Src) {
   149  		return false
   150  	}
   151  
   152  	if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() {
   153  		return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic)
   154  	} else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() {
   155  		return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic)
   156  	}
   157  	return false
   158  }
   159  
   160  func (f *Filter) MatchEnvelope(envelope *Envelope) bool {
   161  	if f.PoW > 0 && envelope.pow < f.PoW {
   162  		return false
   163  	}
   164  
   165  	if f.expectsAsymmetricEncryption() && envelope.isAsymmetric() {
   166  		return f.MatchTopic(envelope.Topic)
   167  	} else if f.expectsSymmetricEncryption() && envelope.IsSymmetric() {
   168  		return f.MatchTopic(envelope.Topic)
   169  	}
   170  	return false
   171  }
   172  
   173  func (f *Filter) MatchTopic(topic TopicType) bool {
   174  	if len(f.Topics) == 0 {
   175  		// any topic matches
   176  		return true
   177  	}
   178  
   179  	for _, t := range f.Topics {
   180  		if t == topic {
   181  			return true
   182  		}
   183  	}
   184  	return false
   185  }
   186  
   187  func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
   188  	if !ValidatePublicKey(a) {
   189  		return false
   190  	} else if !ValidatePublicKey(b) {
   191  		return false
   192  	}
   193  	// the Curve is always the same, just compare the points
   194  	return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
   195  }