gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/whisper/whisperv6/filter_test.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 whisperv6
    18  
    19  import (
    20  	"math/big"
    21  	mrand "math/rand"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  )
    28  
    29  var seed int64
    30  
    31  // InitSingleTest should be called in the beginning of every
    32  // test, which uses RNG, in order to make the tests
    33  // reproduciblity independent of their sequence.
    34  func InitSingleTest() {
    35  	seed = time.Now().Unix()
    36  	mrand.Seed(seed)
    37  }
    38  
    39  type FilterTestCase struct {
    40  	f      *Filter
    41  	id     string
    42  	alive  bool
    43  	msgCnt int
    44  }
    45  
    46  func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
    47  	var f Filter
    48  	f.Messages = make(map[common.Hash]*ReceivedMessage)
    49  
    50  	const topicNum = 8
    51  	f.Topics = make([][]byte, topicNum)
    52  	for i := 0; i < topicNum; i++ {
    53  		f.Topics[i] = make([]byte, 4)
    54  		mrand.Read(f.Topics[i])
    55  		f.Topics[i][0] = 0x01
    56  	}
    57  
    58  	key, err := crypto.GenerateKey()
    59  	if err != nil {
    60  		t.Fatalf("generateFilter 1 failed with seed %d.", seed)
    61  		return nil, err
    62  	}
    63  	f.Src = &key.PublicKey
    64  
    65  	if symmetric {
    66  		f.KeySym = make([]byte, aesKeyLength)
    67  		mrand.Read(f.KeySym)
    68  		f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
    69  	} else {
    70  		f.KeyAsym, err = crypto.GenerateKey()
    71  		if err != nil {
    72  			t.Fatalf("generateFilter 2 failed with seed %d.", seed)
    73  			return nil, err
    74  		}
    75  	}
    76  
    77  	// AcceptP2P & PoW are not set
    78  	return &f, nil
    79  }
    80  
    81  func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase {
    82  	cases := make([]FilterTestCase, SizeTestFilters)
    83  	for i := 0; i < SizeTestFilters; i++ {
    84  		f, _ := generateFilter(t, true)
    85  		cases[i].f = f
    86  		cases[i].alive = mrand.Int()&int(1) == 0
    87  	}
    88  	return cases
    89  }
    90  
    91  func TestInstallFilters(t *testing.T) {
    92  	InitSingleTest()
    93  
    94  	const SizeTestFilters = 256
    95  	w := New(&Config{})
    96  	filters := NewFilters(w)
    97  	tst := generateTestCases(t, SizeTestFilters)
    98  
    99  	var err error
   100  	var j string
   101  	for i := 0; i < SizeTestFilters; i++ {
   102  		j, err = filters.Install(tst[i].f)
   103  		if err != nil {
   104  			t.Fatalf("seed %d: failed to install filter: %s", seed, err)
   105  		}
   106  		tst[i].id = j
   107  		if len(j) != keyIDSize*2 {
   108  			t.Fatalf("seed %d: wrong filter id size [%d]", seed, len(j))
   109  		}
   110  	}
   111  
   112  	for _, testCase := range tst {
   113  		if !testCase.alive {
   114  			filters.Uninstall(testCase.id)
   115  		}
   116  	}
   117  
   118  	for i, testCase := range tst {
   119  		fil := filters.Get(testCase.id)
   120  		exist := fil != nil
   121  		if exist != testCase.alive {
   122  			t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive)
   123  		}
   124  		if exist && fil.PoW != testCase.f.PoW {
   125  			t.Fatalf("seed %d: failed Get: %d, %v, %v", seed, i, exist, testCase.alive)
   126  		}
   127  	}
   128  }
   129  
   130  func TestInstallSymKeyGeneratesHash(t *testing.T) {
   131  	InitSingleTest()
   132  
   133  	w := New(&Config{})
   134  	filters := NewFilters(w)
   135  	filter, _ := generateFilter(t, true)
   136  
   137  	// save the current SymKeyHash for comparison
   138  	initialSymKeyHash := filter.SymKeyHash
   139  
   140  	// ensure the SymKeyHash is invalid, for Install to recreate it
   141  	var invalid common.Hash
   142  	filter.SymKeyHash = invalid
   143  
   144  	_, err := filters.Install(filter)
   145  
   146  	if err != nil {
   147  		t.Fatalf("Error installing the filter: %s", err)
   148  	}
   149  
   150  	for i, b := range filter.SymKeyHash {
   151  		if b != initialSymKeyHash[i] {
   152  			t.Fatalf("The filter's symmetric key hash was not properly generated by Install")
   153  		}
   154  	}
   155  }
   156  
   157  func TestInstallIdenticalFilters(t *testing.T) {
   158  	InitSingleTest()
   159  
   160  	w := New(&Config{})
   161  	filters := NewFilters(w)
   162  	filter1, _ := generateFilter(t, true)
   163  
   164  	// Copy the first filter since some of its fields
   165  	// are randomly gnerated.
   166  	filter2 := &Filter{
   167  		KeySym:   filter1.KeySym,
   168  		Topics:   filter1.Topics,
   169  		PoW:      filter1.PoW,
   170  		AllowP2P: filter1.AllowP2P,
   171  		Messages: make(map[common.Hash]*ReceivedMessage),
   172  	}
   173  
   174  	_, err := filters.Install(filter1)
   175  
   176  	if err != nil {
   177  		t.Fatalf("Error installing the first filter with seed %d: %s", seed, err)
   178  	}
   179  
   180  	_, err = filters.Install(filter2)
   181  
   182  	if err != nil {
   183  		t.Fatalf("Error installing the second filter with seed %d: %s", seed, err)
   184  	}
   185  
   186  	params, err := generateMessageParams()
   187  	if err != nil {
   188  		t.Fatalf("Error generating message parameters with seed %d: %s", seed, err)
   189  	}
   190  
   191  	params.KeySym = filter1.KeySym
   192  	params.Topic = BytesToTopic(filter1.Topics[0])
   193  
   194  	filter1.Src = &params.Src.PublicKey
   195  	filter2.Src = &params.Src.PublicKey
   196  
   197  	sentMessage, err := NewSentMessage(params)
   198  	if err != nil {
   199  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   200  	}
   201  	env, err := sentMessage.Wrap(params)
   202  	if err != nil {
   203  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   204  	}
   205  	msg := env.Open(filter1)
   206  	if msg == nil {
   207  		t.Fatalf("failed to Open with filter1")
   208  	}
   209  
   210  	if !filter1.MatchEnvelope(env) {
   211  		t.Fatalf("failed matching with the first filter")
   212  	}
   213  
   214  	if !filter2.MatchEnvelope(env) {
   215  		t.Fatalf("failed matching with the first filter")
   216  	}
   217  
   218  	if !filter1.MatchMessage(msg) {
   219  		t.Fatalf("failed matching with the second filter")
   220  	}
   221  
   222  	if !filter2.MatchMessage(msg) {
   223  		t.Fatalf("failed matching with the second filter")
   224  	}
   225  }
   226  
   227  func TestInstallFilterWithSymAndAsymKeys(t *testing.T) {
   228  	InitSingleTest()
   229  
   230  	w := New(&Config{})
   231  	filters := NewFilters(w)
   232  	filter1, _ := generateFilter(t, true)
   233  
   234  	asymKey, err := crypto.GenerateKey()
   235  	if err != nil {
   236  		t.Fatalf("Unable to create asymetric keys: %v", err)
   237  	}
   238  
   239  	// Copy the first filter since some of its fields
   240  	// are randomly gnerated.
   241  	filter := &Filter{
   242  		KeySym:   filter1.KeySym,
   243  		KeyAsym:  asymKey,
   244  		Topics:   filter1.Topics,
   245  		PoW:      filter1.PoW,
   246  		AllowP2P: filter1.AllowP2P,
   247  		Messages: make(map[common.Hash]*ReceivedMessage),
   248  	}
   249  
   250  	_, err = filters.Install(filter)
   251  
   252  	if err == nil {
   253  		t.Fatalf("Error detecting that a filter had both an asymmetric and symmetric key, with seed %d", seed)
   254  	}
   255  }
   256  
   257  func TestComparePubKey(t *testing.T) {
   258  	InitSingleTest()
   259  
   260  	key1, err := crypto.GenerateKey()
   261  	if err != nil {
   262  		t.Fatalf("failed to generate first key with seed %d: %s.", seed, err)
   263  	}
   264  	key2, err := crypto.GenerateKey()
   265  	if err != nil {
   266  		t.Fatalf("failed to generate second key with seed %d: %s.", seed, err)
   267  	}
   268  	if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) {
   269  		t.Fatalf("public keys are equal, seed %d.", seed)
   270  	}
   271  
   272  	// generate key3 == key1
   273  	mrand.Seed(seed)
   274  	key3, err := crypto.GenerateKey()
   275  	if err != nil {
   276  		t.Fatalf("failed to generate third key with seed %d: %s.", seed, err)
   277  	}
   278  	if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) {
   279  		t.Fatalf("key1 == key3, seed %d.", seed)
   280  	}
   281  }
   282  
   283  func TestMatchEnvelope(t *testing.T) {
   284  	InitSingleTest()
   285  
   286  	fsym, err := generateFilter(t, true)
   287  	if err != nil {
   288  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   289  	}
   290  
   291  	fasym, err := generateFilter(t, false)
   292  	if err != nil {
   293  		t.Fatalf("failed generateFilter() with seed %d: %s.", seed, err)
   294  	}
   295  
   296  	params, err := generateMessageParams()
   297  	if err != nil {
   298  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   299  	}
   300  
   301  	params.Topic[0] = 0xFF // topic mismatch
   302  
   303  	msg, err := NewSentMessage(params)
   304  	if err != nil {
   305  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   306  	}
   307  	if _, err = msg.Wrap(params); err != nil {
   308  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   309  	}
   310  
   311  	// encrypt symmetrically
   312  	i := mrand.Int() % 4
   313  	fsym.Topics[i] = params.Topic[:]
   314  	fasym.Topics[i] = params.Topic[:]
   315  	msg, err = NewSentMessage(params)
   316  	if err != nil {
   317  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   318  	}
   319  	env, err := msg.Wrap(params)
   320  	if err != nil {
   321  		t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
   322  	}
   323  
   324  	// symmetric + matching topic: match
   325  	match := fsym.MatchEnvelope(env)
   326  	if !match {
   327  		t.Fatalf("failed MatchEnvelope() symmetric with seed %d.", seed)
   328  	}
   329  
   330  	// symmetric + matching topic + insufficient PoW: mismatch
   331  	fsym.PoW = env.PoW() + 1.0
   332  	match = fsym.MatchEnvelope(env)
   333  	if match {
   334  		t.Fatalf("failed MatchEnvelope(symmetric + matching topic + insufficient PoW) asymmetric with seed %d.", seed)
   335  	}
   336  
   337  	// symmetric + matching topic + sufficient PoW: match
   338  	fsym.PoW = env.PoW() / 2
   339  	match = fsym.MatchEnvelope(env)
   340  	if !match {
   341  		t.Fatalf("failed MatchEnvelope(symmetric + matching topic + sufficient PoW) with seed %d.", seed)
   342  	}
   343  
   344  	// symmetric + topics are nil (wildcard): match
   345  	prevTopics := fsym.Topics
   346  	fsym.Topics = nil
   347  	match = fsym.MatchEnvelope(env)
   348  	if !match {
   349  		t.Fatalf("failed MatchEnvelope(symmetric + topics are nil) with seed %d.", seed)
   350  	}
   351  	fsym.Topics = prevTopics
   352  
   353  	// encrypt asymmetrically
   354  	key, err := crypto.GenerateKey()
   355  	if err != nil {
   356  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
   357  	}
   358  	params.KeySym = nil
   359  	params.Dst = &key.PublicKey
   360  	msg, err = NewSentMessage(params)
   361  	if err != nil {
   362  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   363  	}
   364  	env, err = msg.Wrap(params)
   365  	if err != nil {
   366  		t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
   367  	}
   368  
   369  	// encryption method mismatch
   370  	match = fsym.MatchEnvelope(env)
   371  	if match {
   372  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   373  	}
   374  
   375  	// asymmetric + mismatching topic: mismatch
   376  	match = fasym.MatchEnvelope(env)
   377  	if !match {
   378  		t.Fatalf("failed MatchEnvelope(asymmetric + mismatching topic) with seed %d.", seed)
   379  	}
   380  
   381  	// asymmetric + matching topic: match
   382  	fasym.Topics[i] = fasym.Topics[i+1]
   383  	match = fasym.MatchEnvelope(env)
   384  	if !match {
   385  		t.Fatalf("failed MatchEnvelope(asymmetric + matching topic) with seed %d.", seed)
   386  	}
   387  
   388  	// asymmetric + filter without topic (wildcard): match
   389  	fasym.Topics = nil
   390  	match = fasym.MatchEnvelope(env)
   391  	if !match {
   392  		t.Fatalf("failed MatchEnvelope(asymmetric + filter without topic) with seed %d.", seed)
   393  	}
   394  
   395  	// asymmetric + insufficient PoW: mismatch
   396  	fasym.PoW = env.PoW() + 1.0
   397  	match = fasym.MatchEnvelope(env)
   398  	if match {
   399  		t.Fatalf("failed MatchEnvelope(asymmetric + insufficient PoW) with seed %d.", seed)
   400  	}
   401  
   402  	// asymmetric + sufficient PoW: match
   403  	fasym.PoW = env.PoW() / 2
   404  	match = fasym.MatchEnvelope(env)
   405  	if !match {
   406  		t.Fatalf("failed MatchEnvelope(asymmetric + sufficient PoW) with seed %d.", seed)
   407  	}
   408  
   409  	// filter without topic + envelope without topic: match
   410  	env.Topic = TopicType{}
   411  	match = fasym.MatchEnvelope(env)
   412  	if !match {
   413  		t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed)
   414  	}
   415  
   416  	// filter with topic + envelope without topic: mismatch
   417  	fasym.Topics = fsym.Topics
   418  	match = fasym.MatchEnvelope(env)
   419  	if !match {
   420  		// topic mismatch should have no affect, as topics are handled by topic matchers
   421  		t.Fatalf("failed MatchEnvelope(filter without topic + envelope without topic) with seed %d.", seed)
   422  	}
   423  }
   424  
   425  func TestMatchMessageSym(t *testing.T) {
   426  	InitSingleTest()
   427  
   428  	params, err := generateMessageParams()
   429  	if err != nil {
   430  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   431  	}
   432  
   433  	f, err := generateFilter(t, true)
   434  	if err != nil {
   435  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   436  	}
   437  
   438  	const index = 1
   439  	params.KeySym = f.KeySym
   440  	params.Topic = BytesToTopic(f.Topics[index])
   441  
   442  	sentMessage, err := NewSentMessage(params)
   443  	if err != nil {
   444  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   445  	}
   446  	env, err := sentMessage.Wrap(params)
   447  	if err != nil {
   448  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   449  	}
   450  	msg := env.Open(f)
   451  	if msg == nil {
   452  		t.Fatalf("failed Open with seed %d.", seed)
   453  	}
   454  
   455  	// Src: match
   456  	*f.Src.X = *params.Src.PublicKey.X
   457  	*f.Src.Y = *params.Src.PublicKey.Y
   458  	if !f.MatchMessage(msg) {
   459  		t.Fatalf("failed MatchEnvelope(src match) with seed %d.", seed)
   460  	}
   461  
   462  	// insufficient PoW: mismatch
   463  	f.PoW = msg.PoW + 1.0
   464  	if f.MatchMessage(msg) {
   465  		t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed)
   466  	}
   467  
   468  	// sufficient PoW: match
   469  	f.PoW = msg.PoW / 2
   470  	if !f.MatchMessage(msg) {
   471  		t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed)
   472  	}
   473  
   474  	// topic mismatch
   475  	f.Topics[index][0]++
   476  	if !f.MatchMessage(msg) {
   477  		// topic mismatch should have no affect, as topics are handled by topic matchers
   478  		t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed)
   479  	}
   480  	f.Topics[index][0]--
   481  
   482  	// key mismatch
   483  	f.SymKeyHash[0]++
   484  	if f.MatchMessage(msg) {
   485  		t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed)
   486  	}
   487  	f.SymKeyHash[0]--
   488  
   489  	// Src absent: match
   490  	f.Src = nil
   491  	if !f.MatchMessage(msg) {
   492  		t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed)
   493  	}
   494  
   495  	// key hash mismatch
   496  	h := f.SymKeyHash
   497  	f.SymKeyHash = common.Hash{}
   498  	if f.MatchMessage(msg) {
   499  		t.Fatalf("failed MatchEnvelope(key hash mismatch) with seed %d.", seed)
   500  	}
   501  	f.SymKeyHash = h
   502  	if !f.MatchMessage(msg) {
   503  		t.Fatalf("failed MatchEnvelope(key hash match) with seed %d.", seed)
   504  	}
   505  
   506  	// encryption method mismatch
   507  	f.KeySym = nil
   508  	f.KeyAsym, err = crypto.GenerateKey()
   509  	if err != nil {
   510  		t.Fatalf("failed GenerateKey with seed %d: %s.", seed, err)
   511  	}
   512  	if f.MatchMessage(msg) {
   513  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   514  	}
   515  }
   516  
   517  func TestMatchMessageAsym(t *testing.T) {
   518  	InitSingleTest()
   519  
   520  	f, err := generateFilter(t, false)
   521  	if err != nil {
   522  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   523  	}
   524  
   525  	params, err := generateMessageParams()
   526  	if err != nil {
   527  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   528  	}
   529  
   530  	const index = 1
   531  	params.Topic = BytesToTopic(f.Topics[index])
   532  	params.Dst = &f.KeyAsym.PublicKey
   533  	keySymOrig := params.KeySym
   534  	params.KeySym = nil
   535  
   536  	sentMessage, err := NewSentMessage(params)
   537  	if err != nil {
   538  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   539  	}
   540  	env, err := sentMessage.Wrap(params)
   541  	if err != nil {
   542  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   543  	}
   544  	msg := env.Open(f)
   545  	if msg == nil {
   546  		t.Fatalf("failed to open with seed %d.", seed)
   547  	}
   548  
   549  	// Src: match
   550  	*f.Src.X = *params.Src.PublicKey.X
   551  	*f.Src.Y = *params.Src.PublicKey.Y
   552  	if !f.MatchMessage(msg) {
   553  		t.Fatalf("failed MatchMessage(src match) with seed %d.", seed)
   554  	}
   555  
   556  	// insufficient PoW: mismatch
   557  	f.PoW = msg.PoW + 1.0
   558  	if f.MatchMessage(msg) {
   559  		t.Fatalf("failed MatchEnvelope(insufficient PoW) with seed %d.", seed)
   560  	}
   561  
   562  	// sufficient PoW: match
   563  	f.PoW = msg.PoW / 2
   564  	if !f.MatchMessage(msg) {
   565  		t.Fatalf("failed MatchEnvelope(sufficient PoW) with seed %d.", seed)
   566  	}
   567  
   568  	// topic mismatch
   569  	f.Topics[index][0]++
   570  	if !f.MatchMessage(msg) {
   571  		// topic mismatch should have no affect, as topics are handled by topic matchers
   572  		t.Fatalf("failed MatchEnvelope(topic mismatch) with seed %d.", seed)
   573  	}
   574  	f.Topics[index][0]--
   575  
   576  	// key mismatch
   577  	prev := *f.KeyAsym.PublicKey.X
   578  	zero := *big.NewInt(0)
   579  	*f.KeyAsym.PublicKey.X = zero
   580  	if f.MatchMessage(msg) {
   581  		t.Fatalf("failed MatchEnvelope(key mismatch) with seed %d.", seed)
   582  	}
   583  	*f.KeyAsym.PublicKey.X = prev
   584  
   585  	// Src absent: match
   586  	f.Src = nil
   587  	if !f.MatchMessage(msg) {
   588  		t.Fatalf("failed MatchEnvelope(src absent) with seed %d.", seed)
   589  	}
   590  
   591  	// encryption method mismatch
   592  	f.KeySym = keySymOrig
   593  	f.KeyAsym = nil
   594  	if f.MatchMessage(msg) {
   595  		t.Fatalf("failed MatchEnvelope(encryption method mismatch) with seed %d.", seed)
   596  	}
   597  }
   598  
   599  func cloneFilter(orig *Filter) *Filter {
   600  	var clone Filter
   601  	clone.Messages = make(map[common.Hash]*ReceivedMessage)
   602  	clone.Src = orig.Src
   603  	clone.KeyAsym = orig.KeyAsym
   604  	clone.KeySym = orig.KeySym
   605  	clone.Topics = orig.Topics
   606  	clone.PoW = orig.PoW
   607  	clone.AllowP2P = orig.AllowP2P
   608  	clone.SymKeyHash = orig.SymKeyHash
   609  	return &clone
   610  }
   611  
   612  func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope {
   613  	params, err := generateMessageParams()
   614  	if err != nil {
   615  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   616  		return nil
   617  	}
   618  
   619  	params.KeySym = f.KeySym
   620  	params.Topic = BytesToTopic(f.Topics[2])
   621  	sentMessage, err := NewSentMessage(params)
   622  	if err != nil {
   623  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   624  	}
   625  	env, err := sentMessage.Wrap(params)
   626  	if err != nil {
   627  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   628  		return nil
   629  	}
   630  	return env
   631  }
   632  
   633  func TestWatchers(t *testing.T) {
   634  	InitSingleTest()
   635  
   636  	const NumFilters = 16
   637  	const NumMessages = 256
   638  	var i int
   639  	var j uint32
   640  	var e *Envelope
   641  	var x, firstID string
   642  	var err error
   643  
   644  	w := New(&Config{})
   645  	filters := NewFilters(w)
   646  	tst := generateTestCases(t, NumFilters)
   647  	for i = 0; i < NumFilters; i++ {
   648  		tst[i].f.Src = nil
   649  		x, err = filters.Install(tst[i].f)
   650  		if err != nil {
   651  			t.Fatalf("failed to install filter with seed %d: %s.", seed, err)
   652  		}
   653  		tst[i].id = x
   654  		if len(firstID) == 0 {
   655  			firstID = x
   656  		}
   657  	}
   658  
   659  	lastID := x
   660  
   661  	var envelopes [NumMessages]*Envelope
   662  	for i = 0; i < NumMessages; i++ {
   663  		j = mrand.Uint32() % NumFilters
   664  		e = generateCompatibeEnvelope(t, tst[j].f)
   665  		envelopes[i] = e
   666  		tst[j].msgCnt++
   667  	}
   668  
   669  	for i = 0; i < NumMessages; i++ {
   670  		filters.NotifyWatchers(envelopes[i], false)
   671  	}
   672  
   673  	var total int
   674  	var mail []*ReceivedMessage
   675  	var count [NumFilters]int
   676  
   677  	for i = 0; i < NumFilters; i++ {
   678  		mail = tst[i].f.Retrieve()
   679  		count[i] = len(mail)
   680  		total += len(mail)
   681  	}
   682  
   683  	if total != NumMessages {
   684  		t.Fatalf("failed with seed %d: total = %d, want: %d.", seed, total, NumMessages)
   685  	}
   686  
   687  	for i = 0; i < NumFilters; i++ {
   688  		mail = tst[i].f.Retrieve()
   689  		if len(mail) != 0 {
   690  			t.Fatalf("failed with seed %d: i = %d.", seed, i)
   691  		}
   692  
   693  		if tst[i].msgCnt != count[i] {
   694  			t.Fatalf("failed with seed %d: count[%d]: get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
   695  		}
   696  	}
   697  
   698  	// another round with a cloned filter
   699  
   700  	clone := cloneFilter(tst[0].f)
   701  	filters.Uninstall(lastID)
   702  	total = 0
   703  	last := NumFilters - 1
   704  	tst[last].f = clone
   705  	filters.Install(clone)
   706  	for i = 0; i < NumFilters; i++ {
   707  		tst[i].msgCnt = 0
   708  		count[i] = 0
   709  	}
   710  
   711  	// make sure that the first watcher receives at least one message
   712  	e = generateCompatibeEnvelope(t, tst[0].f)
   713  	envelopes[0] = e
   714  	tst[0].msgCnt++
   715  	for i = 1; i < NumMessages; i++ {
   716  		j = mrand.Uint32() % NumFilters
   717  		e = generateCompatibeEnvelope(t, tst[j].f)
   718  		envelopes[i] = e
   719  		tst[j].msgCnt++
   720  	}
   721  
   722  	for i = 0; i < NumMessages; i++ {
   723  		filters.NotifyWatchers(envelopes[i], false)
   724  	}
   725  
   726  	for i = 0; i < NumFilters; i++ {
   727  		mail = tst[i].f.Retrieve()
   728  		count[i] = len(mail)
   729  		total += len(mail)
   730  	}
   731  
   732  	combined := tst[0].msgCnt + tst[last].msgCnt
   733  	if total != NumMessages+count[0] {
   734  		t.Fatalf("failed with seed %d: total = %d, count[0] = %d.", seed, total, count[0])
   735  	}
   736  
   737  	if combined != count[0] {
   738  		t.Fatalf("failed with seed %d: combined = %d, count[0] = %d.", seed, combined, count[0])
   739  	}
   740  
   741  	if combined != count[last] {
   742  		t.Fatalf("failed with seed %d: combined = %d, count[last] = %d.", seed, combined, count[last])
   743  	}
   744  
   745  	for i = 1; i < NumFilters-1; i++ {
   746  		mail = tst[i].f.Retrieve()
   747  		if len(mail) != 0 {
   748  			t.Fatalf("failed with seed %d: i = %d.", seed, i)
   749  		}
   750  
   751  		if tst[i].msgCnt != count[i] {
   752  			t.Fatalf("failed with seed %d: i = %d, get %d, want %d.", seed, i, tst[i].msgCnt, count[i])
   753  		}
   754  	}
   755  
   756  	// test AcceptP2P
   757  
   758  	total = 0
   759  	filters.NotifyWatchers(envelopes[0], true)
   760  
   761  	for i = 0; i < NumFilters; i++ {
   762  		mail = tst[i].f.Retrieve()
   763  		total += len(mail)
   764  	}
   765  
   766  	if total != 0 {
   767  		t.Fatalf("failed with seed %d: total: got %d, want 0.", seed, total)
   768  	}
   769  
   770  	f := filters.Get(firstID)
   771  	if f == nil {
   772  		t.Fatalf("failed to get the filter with seed %d.", seed)
   773  	}
   774  	f.AllowP2P = true
   775  	total = 0
   776  	filters.NotifyWatchers(envelopes[0], true)
   777  
   778  	for i = 0; i < NumFilters; i++ {
   779  		mail = tst[i].f.Retrieve()
   780  		total += len(mail)
   781  	}
   782  
   783  	if total != 1 {
   784  		t.Fatalf("failed with seed %d: total: got %d, want 1.", seed, total)
   785  	}
   786  }
   787  
   788  func TestVariableTopics(t *testing.T) {
   789  	InitSingleTest()
   790  
   791  	const lastTopicByte = 3
   792  	var match bool
   793  	params, err := generateMessageParams()
   794  	if err != nil {
   795  		t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
   796  	}
   797  	msg, err := NewSentMessage(params)
   798  	if err != nil {
   799  		t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
   800  	}
   801  	env, err := msg.Wrap(params)
   802  	if err != nil {
   803  		t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
   804  	}
   805  
   806  	f, err := generateFilter(t, true)
   807  	if err != nil {
   808  		t.Fatalf("failed generateFilter with seed %d: %s.", seed, err)
   809  	}
   810  
   811  	for i := 0; i < 4; i++ {
   812  		env.Topic = BytesToTopic(f.Topics[i])
   813  		match = f.MatchEnvelope(env)
   814  		if !match {
   815  			t.Fatalf("failed MatchEnvelope symmetric with seed %d, step %d.", seed, i)
   816  		}
   817  
   818  		f.Topics[i][lastTopicByte]++
   819  		match = f.MatchEnvelope(env)
   820  		if !match {
   821  			// topic mismatch should have no affect, as topics are handled by topic matchers
   822  			t.Fatalf("MatchEnvelope symmetric with seed %d, step %d.", seed, i)
   823  		}
   824  	}
   825  }