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 }