github.com/ethereum/go-ethereum@v1.16.1/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  	"context"
    21  	"errors"
    22  	"math/big"
    23  	"reflect"
    24  	"runtime"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/consensus/ethash"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/filtermaps"
    32  	"github.com/ethereum/go-ethereum/core/rawdb"
    33  	"github.com/ethereum/go-ethereum/core/types"
    34  	"github.com/ethereum/go-ethereum/ethdb"
    35  	"github.com/ethereum/go-ethereum/event"
    36  	"github.com/ethereum/go-ethereum/internal/ethapi"
    37  	"github.com/ethereum/go-ethereum/params"
    38  	"github.com/ethereum/go-ethereum/rpc"
    39  )
    40  
    41  type testBackend struct {
    42  	db              ethdb.Database
    43  	fm              *filtermaps.FilterMaps
    44  	txFeed          event.Feed
    45  	logsFeed        event.Feed
    46  	rmLogsFeed      event.Feed
    47  	chainFeed       event.Feed
    48  	pendingBlock    *types.Block
    49  	pendingReceipts types.Receipts
    50  }
    51  
    52  func (b *testBackend) ChainConfig() *params.ChainConfig {
    53  	return params.TestChainConfig
    54  }
    55  
    56  func (b *testBackend) CurrentHeader() *types.Header {
    57  	hdr, _ := b.HeaderByNumber(context.TODO(), rpc.LatestBlockNumber)
    58  	return hdr
    59  }
    60  
    61  func (b *testBackend) CurrentBlock() *types.Header {
    62  	return b.CurrentHeader()
    63  }
    64  
    65  func (b *testBackend) ChainDb() ethdb.Database {
    66  	return b.db
    67  }
    68  
    69  func (b *testBackend) GetCanonicalHash(number uint64) common.Hash {
    70  	return rawdb.ReadCanonicalHash(b.db, number)
    71  }
    72  
    73  func (b *testBackend) GetHeader(hash common.Hash, number uint64) *types.Header {
    74  	hdr, _ := b.HeaderByHash(context.Background(), hash)
    75  	return hdr
    76  }
    77  
    78  func (b *testBackend) GetReceiptsByHash(hash common.Hash) types.Receipts {
    79  	r, _ := b.GetReceipts(context.Background(), hash)
    80  	return r
    81  }
    82  
    83  func (b *testBackend) GetRawReceipts(hash common.Hash, number uint64) types.Receipts {
    84  	return rawdb.ReadRawReceipts(b.db, hash, number)
    85  }
    86  
    87  func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
    88  	var (
    89  		hash common.Hash
    90  		num  uint64
    91  	)
    92  	switch blockNr {
    93  	case rpc.LatestBlockNumber:
    94  		hash = rawdb.ReadHeadBlockHash(b.db)
    95  		number := rawdb.ReadHeaderNumber(b.db, hash)
    96  		if number == nil {
    97  			return nil, nil
    98  		}
    99  		num = *number
   100  	case rpc.FinalizedBlockNumber:
   101  		hash = rawdb.ReadFinalizedBlockHash(b.db)
   102  		number := rawdb.ReadHeaderNumber(b.db, hash)
   103  		if number == nil {
   104  			return nil, nil
   105  		}
   106  		num = *number
   107  	case rpc.SafeBlockNumber:
   108  		return nil, errors.New("safe block not found")
   109  	default:
   110  		num = uint64(blockNr)
   111  		hash = rawdb.ReadCanonicalHash(b.db, num)
   112  	}
   113  	return rawdb.ReadHeader(b.db, hash, num), nil
   114  }
   115  
   116  func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   117  	number := rawdb.ReadHeaderNumber(b.db, hash)
   118  	if number == nil {
   119  		return nil, nil
   120  	}
   121  	return rawdb.ReadHeader(b.db, hash, *number), nil
   122  }
   123  
   124  func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
   125  	if body := rawdb.ReadBody(b.db, hash, uint64(number)); body != nil {
   126  		return body, nil
   127  	}
   128  	return nil, errors.New("block body not found")
   129  }
   130  
   131  func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
   132  	if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil {
   133  		if header := rawdb.ReadHeader(b.db, hash, *number); header != nil {
   134  			return rawdb.ReadReceipts(b.db, hash, *number, header.Time, params.TestChainConfig), nil
   135  		}
   136  	}
   137  	return nil, nil
   138  }
   139  
   140  func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
   141  	logs := rawdb.ReadLogs(b.db, hash, number)
   142  	return logs, nil
   143  }
   144  
   145  func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
   146  	return b.txFeed.Subscribe(ch)
   147  }
   148  
   149  func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   150  	return b.rmLogsFeed.Subscribe(ch)
   151  }
   152  
   153  func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   154  	return b.logsFeed.Subscribe(ch)
   155  }
   156  
   157  func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   158  	return b.chainFeed.Subscribe(ch)
   159  }
   160  
   161  func (b *testBackend) CurrentView() *filtermaps.ChainView {
   162  	head := b.CurrentBlock()
   163  	return filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash())
   164  }
   165  
   166  func (b *testBackend) NewMatcherBackend() filtermaps.MatcherBackend {
   167  	return b.fm.NewMatcherBackend()
   168  }
   169  
   170  func (b *testBackend) startFilterMaps(history uint64, disabled bool, params filtermaps.Params) {
   171  	head := b.CurrentBlock()
   172  	chainView := filtermaps.NewChainView(b, head.Number.Uint64(), head.Hash())
   173  	config := filtermaps.Config{
   174  		History:        history,
   175  		Disabled:       disabled,
   176  		ExportFileName: "",
   177  	}
   178  	b.fm, _ = filtermaps.NewFilterMaps(b.db, chainView, 0, 0, params, config)
   179  	b.fm.Start()
   180  	b.fm.WaitIdle()
   181  }
   182  
   183  func (b *testBackend) stopFilterMaps() {
   184  	b.fm.Stop()
   185  	b.fm = nil
   186  }
   187  
   188  func (b *testBackend) setPending(block *types.Block, receipts types.Receipts) {
   189  	b.pendingBlock = block
   190  	b.pendingReceipts = receipts
   191  }
   192  
   193  func (b *testBackend) HistoryPruningCutoff() uint64 {
   194  	return 0
   195  }
   196  
   197  func newTestFilterSystem(db ethdb.Database, cfg Config) (*testBackend, *FilterSystem) {
   198  	backend := &testBackend{db: db}
   199  	sys := NewFilterSystem(backend, cfg)
   200  	return backend, sys
   201  }
   202  
   203  // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events.
   204  // It creates multiple subscriptions:
   205  // - one at the start and should receive all posted chain events and a second (blockHashes)
   206  // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2])
   207  // - one that is created after the second cutoff moment (blockHashes[cutoff2:])
   208  func TestBlockSubscription(t *testing.T) {
   209  	t.Parallel()
   210  
   211  	var (
   212  		db           = rawdb.NewMemoryDatabase()
   213  		backend, sys = newTestFilterSystem(db, Config{})
   214  		api          = NewFilterAPI(sys)
   215  		genesis      = &core.Genesis{
   216  			Config:  params.TestChainConfig,
   217  			BaseFee: big.NewInt(params.InitialBaseFee),
   218  		}
   219  		_, chain, _ = core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 10, func(i int, gen *core.BlockGen) {})
   220  		chainEvents []core.ChainEvent
   221  	)
   222  
   223  	for _, blk := range chain {
   224  		chainEvents = append(chainEvents, core.ChainEvent{Header: blk.Header()})
   225  	}
   226  
   227  	chan0 := make(chan *types.Header)
   228  	sub0 := api.events.SubscribeNewHeads(chan0)
   229  	chan1 := make(chan *types.Header)
   230  	sub1 := api.events.SubscribeNewHeads(chan1)
   231  
   232  	go func() { // simulate client
   233  		i1, i2 := 0, 0
   234  		for i1 != len(chainEvents) || i2 != len(chainEvents) {
   235  			select {
   236  			case header := <-chan0:
   237  				if chainEvents[i1].Header.Hash() != header.Hash() {
   238  					t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Header.Hash(), header.Hash())
   239  				}
   240  				i1++
   241  			case header := <-chan1:
   242  				if chainEvents[i2].Header.Hash() != header.Hash() {
   243  					t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Header.Hash(), header.Hash())
   244  				}
   245  				i2++
   246  			}
   247  		}
   248  
   249  		sub0.Unsubscribe()
   250  		sub1.Unsubscribe()
   251  	}()
   252  
   253  	time.Sleep(1 * time.Second)
   254  	for _, e := range chainEvents {
   255  		backend.chainFeed.Send(e)
   256  	}
   257  
   258  	<-sub0.Err()
   259  	<-sub1.Err()
   260  }
   261  
   262  // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux.
   263  func TestPendingTxFilter(t *testing.T) {
   264  	t.Parallel()
   265  
   266  	var (
   267  		db           = rawdb.NewMemoryDatabase()
   268  		backend, sys = newTestFilterSystem(db, Config{})
   269  		api          = NewFilterAPI(sys)
   270  
   271  		transactions = []*types.Transaction{
   272  			types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   273  			types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   274  			types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   275  			types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   276  			types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   277  		}
   278  
   279  		hashes []common.Hash
   280  	)
   281  
   282  	fid0 := api.NewPendingTransactionFilter(nil)
   283  
   284  	time.Sleep(1 * time.Second)
   285  	backend.txFeed.Send(core.NewTxsEvent{Txs: transactions})
   286  
   287  	timeout := time.Now().Add(1 * time.Second)
   288  	for {
   289  		results, err := api.GetFilterChanges(fid0)
   290  		if err != nil {
   291  			t.Fatalf("Unable to retrieve logs: %v", err)
   292  		}
   293  
   294  		h := results.([]common.Hash)
   295  		hashes = append(hashes, h...)
   296  		if len(hashes) >= len(transactions) {
   297  			break
   298  		}
   299  		// check timeout
   300  		if time.Now().After(timeout) {
   301  			break
   302  		}
   303  
   304  		time.Sleep(100 * time.Millisecond)
   305  	}
   306  
   307  	if len(hashes) != len(transactions) {
   308  		t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes))
   309  		return
   310  	}
   311  	for i := range hashes {
   312  		if hashes[i] != transactions[i].Hash() {
   313  			t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i])
   314  		}
   315  	}
   316  }
   317  
   318  // TestPendingTxFilterFullTx tests whether pending tx filters retrieve all pending transactions that are posted to the event mux.
   319  func TestPendingTxFilterFullTx(t *testing.T) {
   320  	t.Parallel()
   321  
   322  	var (
   323  		db           = rawdb.NewMemoryDatabase()
   324  		backend, sys = newTestFilterSystem(db, Config{})
   325  		api          = NewFilterAPI(sys)
   326  
   327  		transactions = []*types.Transaction{
   328  			types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   329  			types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   330  			types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   331  			types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   332  			types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
   333  		}
   334  
   335  		txs []*ethapi.RPCTransaction
   336  	)
   337  
   338  	fullTx := true
   339  	fid0 := api.NewPendingTransactionFilter(&fullTx)
   340  
   341  	time.Sleep(1 * time.Second)
   342  	backend.txFeed.Send(core.NewTxsEvent{Txs: transactions})
   343  
   344  	timeout := time.Now().Add(1 * time.Second)
   345  	for {
   346  		results, err := api.GetFilterChanges(fid0)
   347  		if err != nil {
   348  			t.Fatalf("Unable to retrieve logs: %v", err)
   349  		}
   350  
   351  		tx := results.([]*ethapi.RPCTransaction)
   352  		txs = append(txs, tx...)
   353  		if len(txs) >= len(transactions) {
   354  			break
   355  		}
   356  		// check timeout
   357  		if time.Now().After(timeout) {
   358  			break
   359  		}
   360  
   361  		time.Sleep(100 * time.Millisecond)
   362  	}
   363  
   364  	if len(txs) != len(transactions) {
   365  		t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(txs))
   366  		return
   367  	}
   368  	for i := range txs {
   369  		if txs[i].Hash != transactions[i].Hash() {
   370  			t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash)
   371  		}
   372  	}
   373  }
   374  
   375  // TestLogFilterCreation test whether a given filter criteria makes sense.
   376  // If not it must return an error.
   377  func TestLogFilterCreation(t *testing.T) {
   378  	var (
   379  		db     = rawdb.NewMemoryDatabase()
   380  		_, sys = newTestFilterSystem(db, Config{})
   381  		api    = NewFilterAPI(sys)
   382  
   383  		testCases = []struct {
   384  			crit    FilterCriteria
   385  			success bool
   386  		}{
   387  			// defaults
   388  			{FilterCriteria{}, true},
   389  			// valid block number range
   390  			{FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true},
   391  			// "mined" block range to pending
   392  			{FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true},
   393  			// from block "higher" than to block
   394  			{FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false},
   395  			// from block "higher" than to block
   396  			{FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false},
   397  			// from block "higher" than to block
   398  			{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false},
   399  			// from block "higher" than to block
   400  			{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false},
   401  			// topics more than 4
   402  			{FilterCriteria{Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, false},
   403  		}
   404  	)
   405  
   406  	for i, test := range testCases {
   407  		id, err := api.NewFilter(test.crit)
   408  		if err != nil && test.success {
   409  			t.Errorf("expected filter creation for case %d to success, got %v", i, err)
   410  		}
   411  		if err == nil {
   412  			api.UninstallFilter(id)
   413  			if !test.success {
   414  				t.Errorf("expected testcase %d to fail with an error", i)
   415  			}
   416  		}
   417  	}
   418  }
   419  
   420  // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error
   421  // when the filter is created.
   422  func TestInvalidLogFilterCreation(t *testing.T) {
   423  	t.Parallel()
   424  
   425  	var (
   426  		db     = rawdb.NewMemoryDatabase()
   427  		_, sys = newTestFilterSystem(db, Config{})
   428  		api    = NewFilterAPI(sys)
   429  	)
   430  
   431  	// different situations where log filter creation should fail.
   432  	// Reason: fromBlock > toBlock
   433  	testCases := []FilterCriteria{
   434  		0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
   435  		1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)},
   436  		2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)},
   437  		3: {Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
   438  		4: {Addresses: make([]common.Address, maxAddresses+1)},
   439  	}
   440  
   441  	for i, test := range testCases {
   442  		if _, err := api.NewFilter(test); err == nil {
   443  			t.Errorf("Expected NewFilter for case #%d to fail", i)
   444  		}
   445  	}
   446  }
   447  
   448  // TestInvalidGetLogsRequest tests invalid getLogs requests
   449  func TestInvalidGetLogsRequest(t *testing.T) {
   450  	t.Parallel()
   451  
   452  	var (
   453  		db        = rawdb.NewMemoryDatabase()
   454  		_, sys    = newTestFilterSystem(db, Config{})
   455  		api       = NewFilterAPI(sys)
   456  		blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
   457  	)
   458  
   459  	// Reason: Cannot specify both BlockHash and FromBlock/ToBlock)
   460  	testCases := []FilterCriteria{
   461  		0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
   462  		1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
   463  		2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
   464  		3: {BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
   465  		4: {BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)},
   466  	}
   467  
   468  	for i, test := range testCases {
   469  		if _, err := api.GetLogs(context.Background(), test); err == nil {
   470  			t.Errorf("Expected Logs for case #%d to fail", i)
   471  		}
   472  	}
   473  }
   474  
   475  // TestInvalidGetRangeLogsRequest tests getLogs with invalid block range
   476  func TestInvalidGetRangeLogsRequest(t *testing.T) {
   477  	t.Parallel()
   478  
   479  	var (
   480  		db     = rawdb.NewMemoryDatabase()
   481  		_, sys = newTestFilterSystem(db, Config{})
   482  		api    = NewFilterAPI(sys)
   483  	)
   484  
   485  	if _, err := api.GetLogs(context.Background(), FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}); err != errInvalidBlockRange {
   486  		t.Errorf("Expected Logs for invalid range return error, but got: %v", err)
   487  	}
   488  }
   489  
   490  // TestLogFilter tests whether log filters match the correct logs that are posted to the event feed.
   491  func TestLogFilter(t *testing.T) {
   492  	t.Parallel()
   493  
   494  	var (
   495  		db           = rawdb.NewMemoryDatabase()
   496  		backend, sys = newTestFilterSystem(db, Config{})
   497  		api          = NewFilterAPI(sys)
   498  
   499  		firstAddr      = common.HexToAddress("0x1111111111111111111111111111111111111111")
   500  		secondAddr     = common.HexToAddress("0x2222222222222222222222222222222222222222")
   501  		thirdAddress   = common.HexToAddress("0x3333333333333333333333333333333333333333")
   502  		notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999")
   503  		firstTopic     = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
   504  		secondTopic    = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222")
   505  		notUsedTopic   = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999")
   506  
   507  		// posted twice, once as regular logs and once as pending logs.
   508  		allLogs = []*types.Log{
   509  			{Address: firstAddr},
   510  			{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1},
   511  			{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1},
   512  			{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2},
   513  			{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3},
   514  		}
   515  
   516  		testCases = []struct {
   517  			crit     FilterCriteria
   518  			expected []*types.Log
   519  			id       rpc.ID
   520  		}{
   521  			// match all
   522  			0: {FilterCriteria{}, allLogs, ""},
   523  			// match none due to no matching addresses
   524  			1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""},
   525  			// match logs based on addresses, ignore topics
   526  			2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""},
   527  			// match none due to no matching topics (match with address)
   528  			3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""},
   529  			// match logs based on addresses and topics
   530  			4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""},
   531  			// match logs based on multiple addresses and "or" topics
   532  			5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""},
   533  			// all "mined" logs with block num >= 2
   534  			6: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""},
   535  			// all "mined" logs
   536  			7: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""},
   537  			// all "mined" logs with 1>= block num <=2 and topic secondTopic
   538  			8: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""},
   539  			// match all logs due to wildcard topic
   540  			9: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""},
   541  		}
   542  	)
   543  
   544  	// create all filters
   545  	for i := range testCases {
   546  		testCases[i].id, _ = api.NewFilter(testCases[i].crit)
   547  	}
   548  
   549  	// raise events
   550  	time.Sleep(1 * time.Second)
   551  	if nsend := backend.logsFeed.Send(allLogs); nsend == 0 {
   552  		t.Fatal("Logs event not delivered")
   553  	}
   554  
   555  	for i, tt := range testCases {
   556  		var fetched []*types.Log
   557  		timeout := time.Now().Add(1 * time.Second)
   558  		for { // fetch all expected logs
   559  			results, err := api.GetFilterChanges(tt.id)
   560  			if err != nil {
   561  				t.Fatalf("test %d: unable to fetch logs: %v", i, err)
   562  			}
   563  
   564  			fetched = append(fetched, results.([]*types.Log)...)
   565  			if len(fetched) >= len(tt.expected) {
   566  				break
   567  			}
   568  			// check timeout
   569  			if time.Now().After(timeout) {
   570  				break
   571  			}
   572  
   573  			time.Sleep(100 * time.Millisecond)
   574  		}
   575  
   576  		if len(fetched) != len(tt.expected) {
   577  			t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched))
   578  			return
   579  		}
   580  
   581  		for l := range fetched {
   582  			if fetched[l].Removed {
   583  				t.Errorf("expected log not to be removed for log %d in case %d", l, i)
   584  			}
   585  			if !reflect.DeepEqual(fetched[l], tt.expected[l]) {
   586  				t.Errorf("invalid log on index %d for case %d", l, i)
   587  			}
   588  		}
   589  	}
   590  }
   591  
   592  // TestPendingTxFilterDeadlock tests if the event loop hangs when pending
   593  // txes arrive at the same time that one of multiple filters is timing out.
   594  // Please refer to #22131 for more details.
   595  func TestPendingTxFilterDeadlock(t *testing.T) {
   596  	t.Parallel()
   597  	timeout := 100 * time.Millisecond
   598  
   599  	var (
   600  		db           = rawdb.NewMemoryDatabase()
   601  		backend, sys = newTestFilterSystem(db, Config{Timeout: timeout})
   602  		api          = NewFilterAPI(sys)
   603  		done         = make(chan struct{})
   604  	)
   605  
   606  	go func() {
   607  		// Bombard feed with txes until signal was received to stop
   608  		i := uint64(0)
   609  		for {
   610  			select {
   611  			case <-done:
   612  				return
   613  			default:
   614  			}
   615  
   616  			tx := types.NewTransaction(i, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil)
   617  			backend.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}})
   618  			i++
   619  		}
   620  	}()
   621  
   622  	// Create a bunch of filters that will
   623  	// timeout either in 100ms or 200ms
   624  	subs := make([]*Subscription, 20)
   625  	for i := range subs {
   626  		fid := api.NewPendingTransactionFilter(nil)
   627  		api.filtersMu.Lock()
   628  		f, ok := api.filters[fid]
   629  		api.filtersMu.Unlock()
   630  		if !ok {
   631  			t.Fatalf("Filter %s should exist", fid)
   632  		}
   633  		subs[i] = f.s
   634  		// Wait for at least one tx to arrive in filter
   635  		for {
   636  			hashes, err := api.GetFilterChanges(fid)
   637  			if err != nil {
   638  				t.Fatalf("Filter should exist: %v\n", err)
   639  			}
   640  			if len(hashes.([]common.Hash)) > 0 {
   641  				break
   642  			}
   643  			runtime.Gosched()
   644  		}
   645  	}
   646  
   647  	// Wait until filters have timed out and have been uninstalled.
   648  	for _, sub := range subs {
   649  		select {
   650  		case <-sub.Err():
   651  		case <-time.After(1 * time.Second):
   652  			t.Fatalf("Filter timeout is hanging")
   653  		}
   654  	}
   655  }