github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/bloombits/matcher_test.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 19:16:35</date>
    10  //</624450078257451008>
    11  
    12  
    13  package bloombits
    14  
    15  import (
    16  	"context"
    17  	"math/rand"
    18  	"sync/atomic"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  )
    24  
    25  const testSectionSize = 4096
    26  
    27  //测试通配符筛选规则(nil)是否可以指定并且处理得很好。
    28  func TestMatcherWildcards(t *testing.T) {
    29  	matcher := NewMatcher(testSectionSize, [][][]byte{
    30  {common.Address{}.Bytes(), common.Address{0x01}.Bytes()}, //默认地址不是通配符
    31  {common.Hash{}.Bytes(), common.Hash{0x01}.Bytes()},       //默认哈希不是通配符
    32  {common.Hash{0x01}.Bytes()},                              //简单规则,健全检查
    33  {common.Hash{0x01}.Bytes(), nil},                         //通配符后缀,删除规则
    34  {nil, common.Hash{0x01}.Bytes()},                         //通配符前缀,删除规则
    35  {nil, nil},                                               //通配符组合,删除规则
    36  {},                                                       //初始化通配符规则,删除规则
    37  nil,                                                      //适当的通配符规则,删除规则
    38  	})
    39  	if len(matcher.filters) != 3 {
    40  		t.Fatalf("filter system size mismatch: have %d, want %d", len(matcher.filters), 3)
    41  	}
    42  	if len(matcher.filters[0]) != 2 {
    43  		t.Fatalf("address clause size mismatch: have %d, want %d", len(matcher.filters[0]), 2)
    44  	}
    45  	if len(matcher.filters[1]) != 2 {
    46  		t.Fatalf("combo topic clause size mismatch: have %d, want %d", len(matcher.filters[1]), 2)
    47  	}
    48  	if len(matcher.filters[2]) != 1 {
    49  		t.Fatalf("singletone topic clause size mismatch: have %d, want %d", len(matcher.filters[2]), 1)
    50  	}
    51  }
    52  
    53  //在单个连续工作流上测试匹配器管道,而不中断。
    54  func TestMatcherContinuous(t *testing.T) {
    55  	testMatcherDiffBatches(t, [][]bloomIndexes{{{10, 20, 30}}}, 0, 100000, false, 75)
    56  	testMatcherDiffBatches(t, [][]bloomIndexes{{{32, 3125, 100}}, {{40, 50, 10}}}, 0, 100000, false, 81)
    57  	testMatcherDiffBatches(t, [][]bloomIndexes{{{4, 8, 11}, {7, 8, 17}}, {{9, 9, 12}, {15, 20, 13}}, {{18, 15, 15}, {12, 10, 4}}}, 0, 10000, false, 36)
    58  }
    59  
    60  //在不断中断和恢复的工作模式下测试匹配器管道
    61  //为了确保数据项只被请求一次。
    62  func TestMatcherIntermittent(t *testing.T) {
    63  	testMatcherDiffBatches(t, [][]bloomIndexes{{{10, 20, 30}}}, 0, 100000, true, 75)
    64  	testMatcherDiffBatches(t, [][]bloomIndexes{{{32, 3125, 100}}, {{40, 50, 10}}}, 0, 100000, true, 81)
    65  	testMatcherDiffBatches(t, [][]bloomIndexes{{{4, 8, 11}, {7, 8, 17}}, {{9, 9, 12}, {15, 20, 13}}, {{18, 15, 15}, {12, 10, 4}}}, 0, 10000, true, 36)
    66  }
    67  
    68  //在随机输入上测试匹配器管道,以期捕获异常。
    69  func TestMatcherRandom(t *testing.T) {
    70  	for i := 0; i < 10; i++ {
    71  		testMatcherBothModes(t, makeRandomIndexes([]int{1}, 50), 0, 10000, 0)
    72  		testMatcherBothModes(t, makeRandomIndexes([]int{3}, 50), 0, 10000, 0)
    73  		testMatcherBothModes(t, makeRandomIndexes([]int{2, 2, 2}, 20), 0, 10000, 0)
    74  		testMatcherBothModes(t, makeRandomIndexes([]int{5, 5, 5}, 50), 0, 10000, 0)
    75  		testMatcherBothModes(t, makeRandomIndexes([]int{4, 4, 4}, 20), 0, 10000, 0)
    76  	}
    77  }
    78  
    79  //如果起始块是
    80  //从8的倍数换档。这需要包括优化
    81  //位集匹配https://github.com/ethereum/go-ethereum/issues/15309。
    82  func TestMatcherShifted(t *testing.T) {
    83  //块0在测试中始终匹配,跳过前8个块
    84  //开始在匹配器位集中获取一个可能的零字节。
    85  
    86  //要保持第二个位集字节为零,筛选器必须只与第一个匹配
    87  //块16中的时间,所以做一个全16位的过滤器就足够了。
    88  
    89  //为了使起始块不被8整除,块号9是第一个
    90  //这将引入移位,而不匹配块0。
    91  	testMatcherBothModes(t, [][]bloomIndexes{{{16, 16, 16}}}, 9, 64, 0)
    92  }
    93  
    94  //所有匹配的测试不会崩溃(内部特殊情况)。
    95  func TestWildcardMatcher(t *testing.T) {
    96  	testMatcherBothModes(t, nil, 0, 10000, 0)
    97  }
    98  
    99  //makerandomndexes生成一个由多个过滤器组成的随机过滤器系统。
   100  //标准,每个都有一个地址和任意的Bloom列表组件
   101  //许多主题Bloom列出组件。
   102  func makeRandomIndexes(lengths []int, max int) [][]bloomIndexes {
   103  	res := make([][]bloomIndexes, len(lengths))
   104  	for i, topics := range lengths {
   105  		res[i] = make([]bloomIndexes, topics)
   106  		for j := 0; j < topics; j++ {
   107  			for k := 0; k < len(res[i][j]); k++ {
   108  				res[i][j][k] = uint(rand.Intn(max-1) + 2)
   109  			}
   110  		}
   111  	}
   112  	return res
   113  }
   114  
   115  //testmacherdiffbatches在单个传递中运行给定的匹配测试,并且
   116  //在批量交付模式下,验证是否处理了所有类型的交付。
   117  //正确无误。
   118  func testMatcherDiffBatches(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, intermittent bool, retrievals uint32) {
   119  	singleton := testMatcher(t, filter, start, blocks, intermittent, retrievals, 1)
   120  	batched := testMatcher(t, filter, start, blocks, intermittent, retrievals, 16)
   121  
   122  	if singleton != batched {
   123  		t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, %v in signleton vs. %v in batched mode", filter, blocks, intermittent, singleton, batched)
   124  	}
   125  }
   126  
   127  //TestMatcherBothModes在连续和
   128  //在间歇模式下,验证请求计数是否匹配。
   129  func testMatcherBothModes(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, retrievals uint32) {
   130  	continuous := testMatcher(t, filter, start, blocks, false, retrievals, 16)
   131  	intermittent := testMatcher(t, filter, start, blocks, true, retrievals, 16)
   132  
   133  	if continuous != intermittent {
   134  		t.Errorf("filter = %v blocks = %v: request count mismatch, %v in continuous vs. %v in intermittent mode", filter, blocks, continuous, intermittent)
   135  	}
   136  }
   137  
   138  //TestMatcher是一个通用测试程序,用于运行给定的Matcher测试并返回
   139  //在不同模式之间进行交叉验证的请求数。
   140  func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, intermittent bool, retrievals uint32, maxReqCount int) uint32 {
   141  //创建一个新的匹配器,模拟显式随机位集
   142  	matcher := NewMatcher(testSectionSize, nil)
   143  	matcher.filters = filter
   144  
   145  	for _, rule := range filter {
   146  		for _, topic := range rule {
   147  			for _, bit := range topic {
   148  				matcher.addScheduler(bit)
   149  			}
   150  		}
   151  	}
   152  //跟踪发出的检索请求数
   153  	var requested uint32
   154  
   155  //启动筛选器和检索器goroutine的匹配会话
   156  	quit := make(chan struct{})
   157  	matches := make(chan uint64, 16)
   158  
   159  	session, err := matcher.Start(context.Background(), start, blocks-1, matches)
   160  	if err != nil {
   161  		t.Fatalf("failed to stat matcher session: %v", err)
   162  	}
   163  	startRetrievers(session, quit, &requested, maxReqCount)
   164  
   165  //遍历所有块并验证管道是否生成正确的匹配项
   166  	for i := start; i < blocks; i++ {
   167  		if expMatch3(filter, i) {
   168  			match, ok := <-matches
   169  			if !ok {
   170  				t.Errorf("filter = %v  blocks = %v  intermittent = %v: expected #%v, results channel closed", filter, blocks, intermittent, i)
   171  				return 0
   172  			}
   173  			if match != i {
   174  				t.Errorf("filter = %v  blocks = %v  intermittent = %v: expected #%v, got #%v", filter, blocks, intermittent, i, match)
   175  			}
   176  //如果我们正在测试间歇模式,请中止并重新启动管道。
   177  			if intermittent {
   178  				session.Close()
   179  				close(quit)
   180  
   181  				quit = make(chan struct{})
   182  				matches = make(chan uint64, 16)
   183  
   184  				session, err = matcher.Start(context.Background(), i+1, blocks-1, matches)
   185  				if err != nil {
   186  					t.Fatalf("failed to stat matcher session: %v", err)
   187  				}
   188  				startRetrievers(session, quit, &requested, maxReqCount)
   189  			}
   190  		}
   191  	}
   192  //确保结果通道在最后一个块后被拆除
   193  	match, ok := <-matches
   194  	if ok {
   195  		t.Errorf("filter = %v  blocks = %v  intermittent = %v: expected closed channel, got #%v", filter, blocks, intermittent, match)
   196  	}
   197  //清理会话并确保与预期的检索计数匹配
   198  	session.Close()
   199  	close(quit)
   200  
   201  	if retrievals != 0 && requested != retrievals {
   202  		t.Errorf("filter = %v  blocks = %v  intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested, retrievals)
   203  	}
   204  	return requested
   205  }
   206  
   207  //StartRetriever启动一批Goroutines,用于侦听节请求
   208  //为他们服务。
   209  func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *uint32, batch int) {
   210  	requests := make(chan chan *Retrieval)
   211  
   212  	for i := 0; i < 10; i++ {
   213  //启动多路复用器以测试多线程执行
   214  		go session.Multiplex(batch, 100*time.Microsecond, requests)
   215  
   216  //启动与上述多路复用器匹配的服务
   217  		go func() {
   218  			for {
   219  //等待服务请求或关闭
   220  				select {
   221  				case <-quit:
   222  					return
   223  
   224  				case request := <-requests:
   225  					task := <-request
   226  
   227  					task.Bitsets = make([][]byte, len(task.Sections))
   228  					for i, section := range task.Sections {
   229  if rand.Int()%4 != 0 { //处理偶尔丢失的交货
   230  							task.Bitsets[i] = generateBitset(task.Bit, section)
   231  							atomic.AddUint32(retrievals, 1)
   232  						}
   233  					}
   234  					request <- task
   235  				}
   236  			}
   237  		}()
   238  	}
   239  }
   240  
   241  //generateBitset为给定的bloom位和节生成旋转的位集
   242  //数字。
   243  func generateBitset(bit uint, section uint64) []byte {
   244  	bitset := make([]byte, testSectionSize/8)
   245  	for i := 0; i < len(bitset); i++ {
   246  		for b := 0; b < 8; b++ {
   247  			blockIdx := section*testSectionSize + uint64(i*8+b)
   248  			bitset[i] += bitset[i]
   249  			if (blockIdx % uint64(bit)) == 0 {
   250  				bitset[i]++
   251  			}
   252  		}
   253  	}
   254  	return bitset
   255  }
   256  
   257  func expMatch1(filter bloomIndexes, i uint64) bool {
   258  	for _, ii := range filter {
   259  		if (i % uint64(ii)) != 0 {
   260  			return false
   261  		}
   262  	}
   263  	return true
   264  }
   265  
   266  func expMatch2(filter []bloomIndexes, i uint64) bool {
   267  	for _, ii := range filter {
   268  		if expMatch1(ii, i) {
   269  			return true
   270  		}
   271  	}
   272  	return false
   273  }
   274  
   275  func expMatch3(filter [][]bloomIndexes, i uint64) bool {
   276  	for _, ii := range filter {
   277  		if !expMatch2(ii, i) {
   278  			return false
   279  		}
   280  	}
   281  	return true
   282  }
   283