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