github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/eth/filters/filter_system_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 12:09:38</date> 10 //</624342635624009728> 11 12 13 package filters 14 15 import ( 16 "context" 17 "fmt" 18 "math/big" 19 "math/rand" 20 "reflect" 21 "testing" 22 "time" 23 24 ethereum "github.com/ethereum/go-ethereum" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus/ethash" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/bloombits" 29 "github.com/ethereum/go-ethereum/core/rawdb" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/event" 33 "github.com/ethereum/go-ethereum/params" 34 "github.com/ethereum/go-ethereum/rpc" 35 ) 36 37 type testBackend struct { 38 mux *event.TypeMux 39 db ethdb.Database 40 sections uint64 41 txFeed *event.Feed 42 rmLogsFeed *event.Feed 43 logsFeed *event.Feed 44 chainFeed *event.Feed 45 } 46 47 func (b *testBackend) ChainDb() ethdb.Database { 48 return b.db 49 } 50 51 func (b *testBackend) EventMux() *event.TypeMux { 52 return b.mux 53 } 54 55 func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { 56 var ( 57 hash common.Hash 58 num uint64 59 ) 60 if blockNr == rpc.LatestBlockNumber { 61 hash = rawdb.ReadHeadBlockHash(b.db) 62 number := rawdb.ReadHeaderNumber(b.db, hash) 63 if number == nil { 64 return nil, nil 65 } 66 num = *number 67 } else { 68 num = uint64(blockNr) 69 hash = rawdb.ReadCanonicalHash(b.db, num) 70 } 71 return rawdb.ReadHeader(b.db, hash, num), nil 72 } 73 74 func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 75 number := rawdb.ReadHeaderNumber(b.db, hash) 76 if number == nil { 77 return nil, nil 78 } 79 return rawdb.ReadHeader(b.db, hash, *number), nil 80 } 81 82 func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 83 if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { 84 return rawdb.ReadReceipts(b.db, hash, *number), nil 85 } 86 return nil, nil 87 } 88 89 func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { 90 number := rawdb.ReadHeaderNumber(b.db, hash) 91 if number == nil { 92 return nil, nil 93 } 94 receipts := rawdb.ReadReceipts(b.db, hash, *number) 95 96 logs := make([][]*types.Log, len(receipts)) 97 for i, receipt := range receipts { 98 logs[i] = receipt.Logs 99 } 100 return logs, nil 101 } 102 103 func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 104 return b.txFeed.Subscribe(ch) 105 } 106 107 func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 108 return b.rmLogsFeed.Subscribe(ch) 109 } 110 111 func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 112 return b.logsFeed.Subscribe(ch) 113 } 114 115 func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 116 return b.chainFeed.Subscribe(ch) 117 } 118 119 func (b *testBackend) BloomStatus() (uint64, uint64) { 120 return params.BloomBitsBlocks, b.sections 121 } 122 123 func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 124 requests := make(chan chan *bloombits.Retrieval) 125 126 go session.Multiplex(16, 0, requests) 127 go func() { 128 for { 129 //等待服务请求或关闭 130 select { 131 case <-ctx.Done(): 132 return 133 134 case request := <-requests: 135 task := <-request 136 137 task.Bitsets = make([][]byte, len(task.Sections)) 138 for i, section := range task.Sections { 139 if rand.Int()%4 != 0 { //处理偶尔丢失的交货 140 head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) 141 task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head) 142 } 143 } 144 request <- task 145 } 146 } 147 }() 148 } 149 150 //testblocksubscription测试块订阅是否返回已发布链事件的块哈希。 151 //它创建多个订阅: 152 //-一个在开始处,应接收所有已发布的链事件和一秒钟(blockhash) 153 //-在切断力矩后创建,在第二个切断力矩后卸载(blockhashes[cutoff1:cutoff2]) 154 //-在第二个截止力矩后创建的一个(blockhashes[cutoff2:] 155 func TestBlockSubscription(t *testing.T) { 156 t.Parallel() 157 158 var ( 159 mux = new(event.TypeMux) 160 db = ethdb.NewMemDatabase() 161 txFeed = new(event.Feed) 162 rmLogsFeed = new(event.Feed) 163 logsFeed = new(event.Feed) 164 chainFeed = new(event.Feed) 165 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 166 api = NewPublicFilterAPI(backend, false) 167 genesis = new(core.Genesis).MustCommit(db) 168 chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) 169 chainEvents = []core.ChainEvent{} 170 ) 171 172 for _, blk := range chain { 173 chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk}) 174 } 175 176 chan0 := make(chan *types.Header) 177 sub0 := api.events.SubscribeNewHeads(chan0) 178 chan1 := make(chan *types.Header) 179 sub1 := api.events.SubscribeNewHeads(chan1) 180 181 go func() { //模拟客户端 182 i1, i2 := 0, 0 183 for i1 != len(chainEvents) || i2 != len(chainEvents) { 184 select { 185 case header := <-chan0: 186 if chainEvents[i1].Hash != header.Hash() { 187 t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash()) 188 } 189 i1++ 190 case header := <-chan1: 191 if chainEvents[i2].Hash != header.Hash() { 192 t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash()) 193 } 194 i2++ 195 } 196 } 197 198 sub0.Unsubscribe() 199 sub1.Unsubscribe() 200 }() 201 202 time.Sleep(1 * time.Second) 203 for _, e := range chainEvents { 204 chainFeed.Send(e) 205 } 206 207 <-sub0.Err() 208 <-sub1.Err() 209 } 210 211 //testpendingtxfilter测试挂起的tx筛选器是否检索发布到事件mux的所有挂起事务。 212 func TestPendingTxFilter(t *testing.T) { 213 t.Parallel() 214 215 var ( 216 mux = new(event.TypeMux) 217 db = ethdb.NewMemDatabase() 218 txFeed = new(event.Feed) 219 rmLogsFeed = new(event.Feed) 220 logsFeed = new(event.Feed) 221 chainFeed = new(event.Feed) 222 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 223 api = NewPublicFilterAPI(backend, false) 224 225 transactions = []*types.Transaction{ 226 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 227 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 228 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 229 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 230 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), 231 } 232 233 hashes []common.Hash 234 ) 235 236 fid0 := api.NewPendingTransactionFilter() 237 238 time.Sleep(1 * time.Second) 239 txFeed.Send(core.NewTxsEvent{Txs: transactions}) 240 241 timeout := time.Now().Add(1 * time.Second) 242 for { 243 results, err := api.GetFilterChanges(fid0) 244 if err != nil { 245 t.Fatalf("Unable to retrieve logs: %v", err) 246 } 247 248 h := results.([]common.Hash) 249 hashes = append(hashes, h...) 250 if len(hashes) >= len(transactions) { 251 break 252 } 253 //检查超时 254 if time.Now().After(timeout) { 255 break 256 } 257 258 time.Sleep(100 * time.Millisecond) 259 } 260 261 if len(hashes) != len(transactions) { 262 t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes)) 263 return 264 } 265 for i := range hashes { 266 if hashes[i] != transactions[i].Hash() { 267 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) 268 } 269 } 270 } 271 272 //testlogfiltercreation测试给定的筛选条件是否有意义。 273 //否则,它必须返回一个错误。 274 func TestLogFilterCreation(t *testing.T) { 275 var ( 276 mux = new(event.TypeMux) 277 db = ethdb.NewMemDatabase() 278 txFeed = new(event.Feed) 279 rmLogsFeed = new(event.Feed) 280 logsFeed = new(event.Feed) 281 chainFeed = new(event.Feed) 282 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 283 api = NewPublicFilterAPI(backend, false) 284 285 testCases = []struct { 286 crit FilterCriteria 287 success bool 288 }{ 289 //默认值 290 {FilterCriteria{}, true}, 291 //有效的块编号范围 292 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, 293 //“已开采”区块范围待定 294 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, 295 //新建已开采和待定区块 296 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true}, 297 //从“高”区到“高”区 298 {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, 299 //从“高”区到“高”区 300 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 301 //从“高”区到“高”区 302 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 303 //从“高”区到“高”区 304 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, 305 } 306 ) 307 308 for i, test := range testCases { 309 _, err := api.NewFilter(test.crit) 310 if test.success && err != nil { 311 t.Errorf("expected filter creation for case %d to success, got %v", i, err) 312 } 313 if !test.success && err == nil { 314 t.Errorf("expected testcase %d to fail with an error", i) 315 } 316 } 317 } 318 319 //TestInvalidLogFilterCreation测试无效的筛选器日志条件是否导致错误 320 //创建筛选器时。 321 func TestInvalidLogFilterCreation(t *testing.T) { 322 t.Parallel() 323 324 var ( 325 mux = new(event.TypeMux) 326 db = ethdb.NewMemDatabase() 327 txFeed = new(event.Feed) 328 rmLogsFeed = new(event.Feed) 329 logsFeed = new(event.Feed) 330 chainFeed = new(event.Feed) 331 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 332 api = NewPublicFilterAPI(backend, false) 333 ) 334 335 //日志过滤器创建失败的不同情况。 336 //原因:FromBlock>ToBlock 337 testCases := []FilterCriteria{ 338 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 339 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 340 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 341 } 342 343 for i, test := range testCases { 344 if _, err := api.NewFilter(test); err == nil { 345 t.Errorf("Expected NewFilter for case #%d to fail", i) 346 } 347 } 348 } 349 350 func TestInvalidGetLogsRequest(t *testing.T) { 351 var ( 352 mux = new(event.TypeMux) 353 db = ethdb.NewMemDatabase() 354 txFeed = new(event.Feed) 355 rmLogsFeed = new(event.Feed) 356 logsFeed = new(event.Feed) 357 chainFeed = new(event.Feed) 358 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 359 api = NewPublicFilterAPI(backend, false) 360 blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 361 ) 362 363 //原因:不能同时指定blockhash和fromblock/toblock) 364 testCases := []FilterCriteria{ 365 0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)}, 366 1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)}, 367 2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 368 } 369 370 for i, test := range testCases { 371 if _, err := api.GetLogs(context.Background(), test); err == nil { 372 t.Errorf("Expected Logs for case #%d to fail", i) 373 } 374 } 375 } 376 377 //testlogfilter测试日志筛选器是否匹配发布到事件馈送的正确日志。 378 func TestLogFilter(t *testing.T) { 379 t.Parallel() 380 381 var ( 382 mux = new(event.TypeMux) 383 db = ethdb.NewMemDatabase() 384 txFeed = new(event.Feed) 385 rmLogsFeed = new(event.Feed) 386 logsFeed = new(event.Feed) 387 chainFeed = new(event.Feed) 388 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 389 api = NewPublicFilterAPI(backend, false) 390 391 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 392 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 393 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 394 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 395 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 396 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 397 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 398 399 //发布两次,一次作为vm.logs,一次作为core.pendinglogsevent 400 allLogs = []*types.Log{ 401 {Address: firstAddr}, 402 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 403 {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 404 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, 405 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, 406 } 407 408 expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} 409 expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} 410 411 testCases = []struct { 412 crit FilterCriteria 413 expected []*types.Log 414 id rpc.ID 415 }{ 416 //全部匹配 417 0: {FilterCriteria{}, allLogs, ""}, 418 //由于没有匹配的地址而不匹配 419 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""}, 420 //根据地址匹配日志,忽略主题 421 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, 422 //由于没有匹配的主题(与地址匹配),因此不匹配 423 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, 424 //根据地址和主题匹配日志 425 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, 426 //基于多个地址和“或”主题匹配日志 427 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, 428 //在挂起块中登录 429 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, 430 //块数大于等于2或挂起日志的挖掘日志 431 7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""}, 432 //块数大于等于2的所有“已开采”日志 433 8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, 434 //所有“开采”的原木 435 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, 436 //所有“已挖掘”日志,其中1>=block num<=2和topic secondtopic 437 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, 438 //主题为FirstTopic的所有“已挖掘”和挂起日志 439 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, 440 //根据通配符主题匹配所有日志 441 12: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""}, 442 } 443 ) 444 445 //创建所有筛选器 446 for i := range testCases { 447 testCases[i].id, _ = api.NewFilter(testCases[i].crit) 448 } 449 450 //提高事件 451 time.Sleep(1 * time.Second) 452 if nsend := logsFeed.Send(allLogs); nsend == 0 { 453 t.Fatal("Shoud have at least one subscription") 454 } 455 if err := mux.Post(core.PendingLogsEvent{Logs: allLogs}); err != nil { 456 t.Fatal(err) 457 } 458 459 for i, tt := range testCases { 460 var fetched []*types.Log 461 timeout := time.Now().Add(1 * time.Second) 462 for { //获取所有预期日志 463 results, err := api.GetFilterChanges(tt.id) 464 if err != nil { 465 t.Fatalf("Unable to fetch logs: %v", err) 466 } 467 468 fetched = append(fetched, results.([]*types.Log)...) 469 if len(fetched) >= len(tt.expected) { 470 break 471 } 472 //检查超时 473 if time.Now().After(timeout) { 474 break 475 } 476 477 time.Sleep(100 * time.Millisecond) 478 } 479 480 if len(fetched) != len(tt.expected) { 481 t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 482 return 483 } 484 485 for l := range fetched { 486 if fetched[l].Removed { 487 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 488 } 489 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 490 t.Errorf("invalid log on index %d for case %d", l, i) 491 } 492 } 493 } 494 } 495 496 //testpendinglogssubscription测试订阅是否接收到发布到事件源的正确挂起日志。 497 func TestPendingLogsSubscription(t *testing.T) { 498 t.Parallel() 499 500 var ( 501 mux = new(event.TypeMux) 502 db = ethdb.NewMemDatabase() 503 txFeed = new(event.Feed) 504 rmLogsFeed = new(event.Feed) 505 logsFeed = new(event.Feed) 506 chainFeed = new(event.Feed) 507 backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed} 508 api = NewPublicFilterAPI(backend, false) 509 510 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 511 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 512 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 513 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 514 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 515 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 516 thirdTopic = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333") 517 fourthTopic = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444") 518 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 519 520 allLogs = []core.PendingLogsEvent{ 521 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}}, 522 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}}, 523 {Logs: []*types.Log{{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}}, 524 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}}, 525 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}}, 526 {Logs: []*types.Log{ 527 {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 528 {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, 529 {Address: thirdAddress, Topics: []common.Hash{fourthTopic}, BlockNumber: 5}, 530 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 531 }}, 532 } 533 534 convertLogs = func(pl []core.PendingLogsEvent) []*types.Log { 535 var logs []*types.Log 536 for _, l := range pl { 537 logs = append(logs, l.Logs...) 538 } 539 return logs 540 } 541 542 testCases = []struct { 543 crit ethereum.FilterQuery 544 expected []*types.Log 545 c chan []*types.Log 546 sub *Subscription 547 }{ 548 //全部匹配 549 {ethereum.FilterQuery{}, convertLogs(allLogs), nil, nil}, 550 //由于没有匹配的地址而不匹配 551 {ethereum.FilterQuery{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, nil, nil}, 552 //根据地址匹配日志,忽略主题 553 {ethereum.FilterQuery{Addresses: []common.Address{firstAddr}}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 554 //由于没有匹配的主题(与地址匹配),因此不匹配 555 {ethereum.FilterQuery{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, nil, nil}, 556 //根据地址和主题匹配日志 557 {ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[3:5]), allLogs[5].Logs[0]), nil, nil}, 558 //基于多个地址和“或”主题匹配日志 559 {ethereum.FilterQuery{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[2:5]), allLogs[5].Logs[0]), nil, nil}, 560 //对于使用新的***筛选器创建的筛选器,将忽略块号,这些块号将在状态更改时返回与给定条件匹配的所有日志。 561 {ethereum.FilterQuery{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(2), ToBlock: big.NewInt(3)}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 562 //多个挂起的日志,应该只匹配块5中日志中的2个主题 563 {ethereum.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, fourthTopic}}}, []*types.Log{allLogs[5].Logs[0], allLogs[5].Logs[2]}, nil, nil}, 564 } 565 ) 566 567 //创建所有订阅,这将确保在发布事件之前创建所有订阅。 568 //在速度较慢的计算机上,这可能会导致在以下时间之后创建订阅时丢失事件 569 //(某些)事件已发布。 570 for i := range testCases { 571 testCases[i].c = make(chan []*types.Log) 572 testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) 573 } 574 575 for n, test := range testCases { 576 i := n 577 tt := test 578 go func() { 579 var fetched []*types.Log 580 fetchLoop: 581 for { 582 logs := <-tt.c 583 fetched = append(fetched, logs...) 584 if len(fetched) >= len(tt.expected) { 585 break fetchLoop 586 } 587 } 588 589 if len(fetched) != len(tt.expected) { 590 panic(fmt.Sprintf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched))) 591 } 592 593 for l := range fetched { 594 if fetched[l].Removed { 595 panic(fmt.Sprintf("expected log not to be removed for log %d in case %d", l, i)) 596 } 597 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 598 panic(fmt.Sprintf("invalid log on index %d for case %d", l, i)) 599 } 600 } 601 }() 602 } 603 604 //提高事件 605 time.Sleep(1 * time.Second) 606 //所有日志都是core.pendingLogSevent类型 607 for _, l := range allLogs { 608 if err := mux.Post(l); err != nil { 609 t.Fatal(err) 610 } 611 } 612 } 613