github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/eth/filters/filter_system_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 filters 18 19 import ( 20 "math/big" 21 "reflect" 22 "testing" 23 "time" 24 25 "golang.org/x/net/context" 26 27 "github.com/atheioschain/go-atheios/common" 28 "github.com/atheioschain/go-atheios/core" 29 "github.com/atheioschain/go-atheios/core/types" 30 "github.com/atheioschain/go-atheios/ethdb" 31 "github.com/atheioschain/go-atheios/event" 32 "github.com/atheioschain/go-atheios/params" 33 "github.com/atheioschain/go-atheios/rpc" 34 ) 35 36 type testBackend struct { 37 mux *event.TypeMux 38 db ethdb.Database 39 } 40 41 func (b *testBackend) ChainDb() ethdb.Database { 42 return b.db 43 } 44 45 func (b *testBackend) EventMux() *event.TypeMux { 46 return b.mux 47 } 48 49 func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { 50 var hash common.Hash 51 var num uint64 52 if blockNr == rpc.LatestBlockNumber { 53 hash = core.GetHeadBlockHash(b.db) 54 num = core.GetBlockNumber(b.db, hash) 55 } else { 56 num = uint64(blockNr) 57 hash = core.GetCanonicalHash(b.db, num) 58 } 59 return core.GetHeader(b.db, hash, num), nil 60 } 61 62 func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { 63 num := core.GetBlockNumber(b.db, blockHash) 64 return core.GetBlockReceipts(b.db, blockHash, num), nil 65 } 66 67 // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. 68 // It creates multiple subscriptions: 69 // - one at the start and should receive all posted chain events and a second (blockHashes) 70 // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2]) 71 // - one that is created after the second cutoff moment (blockHashes[cutoff2:]) 72 func TestBlockSubscription(t *testing.T) { 73 t.Parallel() 74 75 var ( 76 mux = new(event.TypeMux) 77 db, _ = ethdb.NewMemDatabase() 78 backend = &testBackend{mux, db} 79 api = NewPublicFilterAPI(backend, false) 80 81 genesis = core.WriteGenesisBlockForTesting(db) 82 chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {}) 83 chainEvents = []core.ChainEvent{} 84 ) 85 86 for _, blk := range chain { 87 chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk}) 88 } 89 90 chan0 := make(chan *types.Header) 91 sub0 := api.events.SubscribeNewHeads(chan0) 92 chan1 := make(chan *types.Header) 93 sub1 := api.events.SubscribeNewHeads(chan1) 94 95 go func() { // simulate client 96 i1, i2 := 0, 0 97 for i1 != len(chainEvents) || i2 != len(chainEvents) { 98 select { 99 case header := <-chan0: 100 if chainEvents[i1].Hash != header.Hash() { 101 t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash()) 102 } 103 i1++ 104 case header := <-chan1: 105 if chainEvents[i2].Hash != header.Hash() { 106 t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash()) 107 } 108 i2++ 109 } 110 } 111 112 sub0.Unsubscribe() 113 sub1.Unsubscribe() 114 }() 115 116 time.Sleep(1 * time.Second) 117 for _, e := range chainEvents { 118 mux.Post(e) 119 } 120 121 <-sub0.Err() 122 <-sub1.Err() 123 } 124 125 // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux. 126 func TestPendingTxFilter(t *testing.T) { 127 t.Parallel() 128 129 var ( 130 mux = new(event.TypeMux) 131 db, _ = ethdb.NewMemDatabase() 132 backend = &testBackend{mux, db} 133 api = NewPublicFilterAPI(backend, false) 134 135 transactions = []*types.Transaction{ 136 types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), 137 types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), 138 types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), 139 types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), 140 types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), 141 } 142 143 hashes []common.Hash 144 ) 145 146 fid0 := api.NewPendingTransactionFilter() 147 148 time.Sleep(1 * time.Second) 149 for _, tx := range transactions { 150 ev := core.TxPreEvent{Tx: tx} 151 mux.Post(ev) 152 } 153 154 for { 155 results, err := api.GetFilterChanges(fid0) 156 if err != nil { 157 t.Fatalf("Unable to retrieve logs: %v", err) 158 } 159 160 h := results.([]common.Hash) 161 hashes = append(hashes, h...) 162 if len(hashes) >= len(transactions) { 163 break 164 } 165 166 time.Sleep(100 * time.Millisecond) 167 } 168 169 for i := range hashes { 170 if hashes[i] != transactions[i].Hash() { 171 t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i]) 172 } 173 } 174 } 175 176 // TestLogFilterCreation test whether a given filter criteria makes sense. 177 // If not it must return an error. 178 func TestLogFilterCreation(t *testing.T) { 179 var ( 180 mux = new(event.TypeMux) 181 db, _ = ethdb.NewMemDatabase() 182 backend = &testBackend{mux, db} 183 api = NewPublicFilterAPI(backend, false) 184 185 testCases = []struct { 186 crit FilterCriteria 187 success bool 188 }{ 189 // defaults 190 {FilterCriteria{}, true}, 191 // valid block number range 192 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true}, 193 // "mined" block range to pending 194 {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true}, 195 // new mined and pending blocks 196 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true}, 197 // from block "higher" than to block 198 {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false}, 199 // from block "higher" than to block 200 {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 201 // from block "higher" than to block 202 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, 203 // from block "higher" than to block 204 {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, 205 } 206 ) 207 208 for i, test := range testCases { 209 _, err := api.NewFilter(test.crit) 210 if test.success && err != nil { 211 t.Errorf("expected filter creation for case %d to success, got %v", i, err) 212 } 213 if !test.success && err == nil { 214 t.Errorf("expected testcase %d to fail with an error", i) 215 } 216 } 217 } 218 219 // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error 220 // when the filter is created. 221 func TestInvalidLogFilterCreation(t *testing.T) { 222 t.Parallel() 223 224 var ( 225 mux = new(event.TypeMux) 226 db, _ = ethdb.NewMemDatabase() 227 backend = &testBackend{mux, db} 228 api = NewPublicFilterAPI(backend, false) 229 ) 230 231 // different situations where log filter creation should fail. 232 // Reason: fromBlock > toBlock 233 testCases := []FilterCriteria{ 234 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 235 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 236 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 237 } 238 239 for i, test := range testCases { 240 if _, err := api.NewFilter(test); err == nil { 241 t.Errorf("Expected NewFilter for case #%d to fail", i) 242 } 243 } 244 } 245 246 // TestLogFilter tests whether log filters match the correct logs that are posted to the event mux. 247 func TestLogFilter(t *testing.T) { 248 t.Parallel() 249 250 var ( 251 mux = new(event.TypeMux) 252 db, _ = ethdb.NewMemDatabase() 253 backend = &testBackend{mux, db} 254 api = NewPublicFilterAPI(backend, false) 255 256 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 257 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 258 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 259 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 260 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 261 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 262 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 263 264 // posted twice, once as vm.Logs and once as core.PendingLogsEvent 265 allLogs = []*types.Log{ 266 {Address: firstAddr}, 267 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 268 {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, 269 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, 270 {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, 271 } 272 273 expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} 274 expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} 275 276 testCases = []struct { 277 crit FilterCriteria 278 expected []*types.Log 279 id rpc.ID 280 }{ 281 // match all 282 0: {FilterCriteria{}, allLogs, ""}, 283 // match none due to no matching addresses 284 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{allLogs[0].Topics}}, []*types.Log{}, ""}, 285 // match logs based on addresses, ignore topics 286 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, 287 // match none due to no matching topics (match with address) 288 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, 289 // match logs based on addresses and topics 290 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, 291 // match logs based on multiple addresses and "or" topics 292 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, 293 // logs in the pending block 294 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, 295 // mined logs with block num >= 2 or pending logs 296 7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""}, 297 // all "mined" logs with block num >= 2 298 8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""}, 299 // all "mined" logs 300 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, 301 // all "mined" logs with 1>= block num <=2 and topic secondTopic 302 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, 303 // all "mined" and pending logs with topic firstTopic 304 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, 305 } 306 ) 307 308 // create all filters 309 for i := range testCases { 310 testCases[i].id, _ = api.NewFilter(testCases[i].crit) 311 } 312 313 // raise events 314 time.Sleep(1 * time.Second) 315 if err := mux.Post(allLogs); err != nil { 316 t.Fatal(err) 317 } 318 if err := mux.Post(core.PendingLogsEvent{Logs: allLogs}); err != nil { 319 t.Fatal(err) 320 } 321 322 for i, tt := range testCases { 323 var fetched []*types.Log 324 for { // fetch all expected logs 325 results, err := api.GetFilterChanges(tt.id) 326 if err != nil { 327 t.Fatalf("Unable to fetch logs: %v", err) 328 } 329 330 fetched = append(fetched, results.([]*types.Log)...) 331 if len(fetched) >= len(tt.expected) { 332 break 333 } 334 335 time.Sleep(100 * time.Millisecond) 336 } 337 338 if len(fetched) != len(tt.expected) { 339 t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 340 return 341 } 342 343 for l := range fetched { 344 if fetched[l].Removed { 345 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 346 } 347 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 348 t.Errorf("invalid log on index %d for case %d", l, i) 349 } 350 } 351 } 352 } 353 354 // TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event mux. 355 func TestPendingLogsSubscription(t *testing.T) { 356 t.Parallel() 357 358 var ( 359 mux = new(event.TypeMux) 360 db, _ = ethdb.NewMemDatabase() 361 backend = &testBackend{mux, db} 362 api = NewPublicFilterAPI(backend, false) 363 364 firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") 365 secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") 366 thirdAddress = common.HexToAddress("0x3333333333333333333333333333333333333333") 367 notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999") 368 firstTopic = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") 369 secondTopic = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") 370 thirdTopic = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333") 371 forthTopic = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444") 372 notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") 373 374 allLogs = []core.PendingLogsEvent{ 375 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}}, 376 {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}}, 377 {Logs: []*types.Log{{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}}, 378 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}}, 379 {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}}, 380 {Logs: []*types.Log{ 381 {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 382 {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, 383 {Address: thirdAddress, Topics: []common.Hash{forthTopic}, BlockNumber: 5}, 384 {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, 385 }}, 386 } 387 388 convertLogs = func(pl []core.PendingLogsEvent) []*types.Log { 389 var logs []*types.Log 390 for _, l := range pl { 391 logs = append(logs, l.Logs...) 392 } 393 return logs 394 } 395 396 testCases = []struct { 397 crit FilterCriteria 398 expected []*types.Log 399 c chan []*types.Log 400 sub *Subscription 401 }{ 402 // match all 403 {FilterCriteria{}, convertLogs(allLogs), nil, nil}, 404 // match none due to no matching addresses 405 {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{{}}}, []*types.Log{}, nil, nil}, 406 // match logs based on addresses, ignore topics 407 {FilterCriteria{Addresses: []common.Address{firstAddr}}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 408 // match none due to no matching topics (match with address) 409 {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, nil, nil}, 410 // match logs based on addresses and topics 411 {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[3:5]), allLogs[5].Logs[0]), nil, nil}, 412 // match logs based on multiple addresses and "or" topics 413 {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[2:5]), allLogs[5].Logs[0]), nil, nil}, 414 // block numbers are ignored for filters created with New***Filter, these return all logs that match the given criteria when the state changes 415 {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(2), ToBlock: big.NewInt(3)}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, 416 // multiple pending logs, should match only 2 topics from the logs in block 5 417 {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, forthTopic}}}, []*types.Log{allLogs[5].Logs[0], allLogs[5].Logs[2]}, nil, nil}, 418 } 419 ) 420 421 // create all subscriptions, this ensures all subscriptions are created before the events are posted. 422 // on slow machines this could otherwise lead to missing events when the subscription is created after 423 // (some) events are posted. 424 for i := range testCases { 425 testCases[i].c = make(chan []*types.Log) 426 testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) 427 } 428 429 for n, test := range testCases { 430 i := n 431 tt := test 432 go func() { 433 var fetched []*types.Log 434 fetchLoop: 435 for { 436 logs := <-tt.c 437 fetched = append(fetched, logs...) 438 if len(fetched) >= len(tt.expected) { 439 break fetchLoop 440 } 441 } 442 443 if len(fetched) != len(tt.expected) { 444 t.Fatalf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)) 445 } 446 447 for l := range fetched { 448 if fetched[l].Removed { 449 t.Errorf("expected log not to be removed for log %d in case %d", l, i) 450 } 451 if !reflect.DeepEqual(fetched[l], tt.expected[l]) { 452 t.Errorf("invalid log on index %d for case %d", l, i) 453 } 454 } 455 }() 456 } 457 458 // raise events 459 time.Sleep(1 * time.Second) 460 for _, l := range allLogs { 461 if err := mux.Post(l); err != nil { 462 t.Fatal(err) 463 } 464 } 465 }