github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/bloombits/matcher_test.go (about)

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