github.com/dominant-strategies/go-quai@v0.28.2/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  	"fmt"
    22  	"math/big"
    23  	"math/rand"
    24  	"reflect"
    25  	"runtime"
    26  	"testing"
    27  	"time"
    28  
    29  	quai "github.com/dominant-strategies/go-quai"
    30  	"github.com/dominant-strategies/go-quai/common"
    31  	"github.com/dominant-strategies/go-quai/consensus/progpow"
    32  	"github.com/dominant-strategies/go-quai/core"
    33  	"github.com/dominant-strategies/go-quai/core/bloombits"
    34  	"github.com/dominant-strategies/go-quai/core/rawdb"
    35  	"github.com/dominant-strategies/go-quai/core/types"
    36  	"github.com/dominant-strategies/go-quai/ethdb"
    37  	"github.com/dominant-strategies/go-quai/event"
    38  	"github.com/dominant-strategies/go-quai/params"
    39  	"github.com/dominant-strategies/go-quai/rpc"
    40  )
    41  
    42  var (
    43  	deadline = 5 * time.Minute
    44  )
    45  
    46  type testBackend struct {
    47  	mux             *event.TypeMux
    48  	db              ethdb.Database
    49  	sections        uint64
    50  	txFeed          event.Feed
    51  	logsFeed        event.Feed
    52  	rmLogsFeed      event.Feed
    53  	pendingLogsFeed event.Feed
    54  	chainFeed       event.Feed
    55  }
    56  
    57  func (b *testBackend) ChainDb() ethdb.Database {
    58  	return b.db
    59  }
    60  
    61  func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) {
    62  	var (
    63  		hash common.Hash
    64  		num  uint64
    65  	)
    66  	if blockNr == rpc.LatestBlockNumber {
    67  		hash = rawdb.ReadHeadBlockHash(b.db)
    68  		number := rawdb.ReadHeaderNumber(b.db, hash)
    69  		if number == nil {
    70  			return nil, nil
    71  		}
    72  		num = *number
    73  	} else {
    74  		num = uint64(blockNr)
    75  		hash = rawdb.ReadCanonicalHash(b.db, num)
    76  	}
    77  	return rawdb.ReadHeader(b.db, hash, num), nil
    78  }
    79  
    80  func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
    81  	number := rawdb.ReadHeaderNumber(b.db, hash)
    82  	if number == nil {
    83  		return nil, nil
    84  	}
    85  	return rawdb.ReadHeader(b.db, hash, *number), nil
    86  }
    87  
    88  func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
    89  	if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil {
    90  		return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil
    91  	}
    92  	return nil, nil
    93  }
    94  
    95  func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
    96  	number := rawdb.ReadHeaderNumber(b.db, hash)
    97  	if number == nil {
    98  		return nil, nil
    99  	}
   100  	receipts := rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig)
   101  
   102  	logs := make([][]*types.Log, len(receipts))
   103  	for i, receipt := range receipts {
   104  		logs[i] = receipt.Logs
   105  	}
   106  	return logs, nil
   107  }
   108  
   109  func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
   110  	return b.txFeed.Subscribe(ch)
   111  }
   112  
   113  func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   114  	return b.rmLogsFeed.Subscribe(ch)
   115  }
   116  
   117  func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   118  	return b.logsFeed.Subscribe(ch)
   119  }
   120  
   121  func (b *testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
   122  	return b.pendingLogsFeed.Subscribe(ch)
   123  }
   124  
   125  func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   126  	return b.chainFeed.Subscribe(ch)
   127  }
   128  
   129  func (b *testBackend) BloomStatus() (uint64, uint64) {
   130  	return params.BloomBitsBlocks, b.sections
   131  }
   132  
   133  func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
   134  	requests := make(chan chan *bloombits.Retrieval)
   135  
   136  	go session.Multiplex(16, 0, requests)
   137  	go func() {
   138  		for {
   139  			// Wait for a service request or a shutdown
   140  			select {
   141  			case <-ctx.Done():
   142  				return
   143  
   144  			case request := <-requests:
   145  				task := <-request
   146  
   147  				task.Bitsets = make([][]byte, len(task.Sections))
   148  				for i, section := range task.Sections {
   149  					if rand.Int()%4 != 0 { // Handle occasional missing deliveries
   150  						head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1)
   151  						task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head)
   152  					}
   153  				}
   154  				request <- task
   155  			}
   156  		}
   157  	}()
   158  }
   159  
   160  // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events.
   161  // It creates multiple subscriptions:
   162  // - one at the start and should receive all posted chain events and a second (blockHashes)
   163  // - one that is created after a cutoff moment and uninstalled after a second cutoff moment (blockHashes[cutoff1:cutoff2])
   164  // - one that is created after the second cutoff moment (blockHashes[cutoff2:])
   165  func TestBlockSubscription(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	var (
   169  		db          = rawdb.NewMemoryDatabase()
   170  		backend     = &testBackend{db: db}
   171  		api         = NewPublicFilterAPI(backend, false, deadline)
   172  		genesis     = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db)
   173  		chain, _    = core.GenerateChain(params.TestChainConfig, genesis, progpow.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {})
   174  		chainEvents = []core.ChainEvent{}
   175  	)
   176  
   177  	for _, blk := range chain {
   178  		chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk})
   179  	}
   180  
   181  	chan0 := make(chan *types.Header)
   182  	sub0 := api.events.SubscribeNewHeads(chan0)
   183  	chan1 := make(chan *types.Header)
   184  	sub1 := api.events.SubscribeNewHeads(chan1)
   185  
   186  	go func() { // simulate client
   187  		i1, i2 := 0, 0
   188  		for i1 != len(chainEvents) || i2 != len(chainEvents) {
   189  			select {
   190  			case header := <-chan0:
   191  				if chainEvents[i1].Hash != header.Hash() {
   192  					t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash())
   193  				}
   194  				i1++
   195  			case header := <-chan1:
   196  				if chainEvents[i2].Hash != header.Hash() {
   197  					t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash())
   198  				}
   199  				i2++
   200  			}
   201  		}
   202  
   203  		sub0.Unsubscribe()
   204  		sub1.Unsubscribe()
   205  	}()
   206  
   207  	time.Sleep(1 * time.Second)
   208  	for _, e := range chainEvents {
   209  		backend.chainFeed.Send(e)
   210  	}
   211  
   212  	<-sub0.Err()
   213  	<-sub1.Err()
   214  }
   215  
   216  // TestPendingTxFilter tests whether pending tx filters retrieve all pending transactions that are posted to the event mux.
   217  func TestPendingTxFilter(t *testing.T) {
   218  	t.Parallel()
   219  
   220  	var (
   221  		db      = rawdb.NewMemoryDatabase()
   222  		backend = &testBackend{db: db}
   223  		api     = NewPublicFilterAPI(backend, false, deadline)
   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  	backend.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  		// check timeout
   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 test whether a given filter criteria makes sense.
   273  // If not it must return an error.
   274  func TestLogFilterCreation(t *testing.T) {
   275  	var (
   276  		db      = rawdb.NewMemoryDatabase()
   277  		backend = &testBackend{db: db}
   278  		api     = NewPublicFilterAPI(backend, false, deadline)
   279  
   280  		testCases = []struct {
   281  			crit    FilterCriteria
   282  			success bool
   283  		}{
   284  			// defaults
   285  			{FilterCriteria{}, true},
   286  			// valid block number range
   287  			{FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2)}, true},
   288  			// "mined" block range to pending
   289  			{FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, true},
   290  			// new mined and pending blocks
   291  			{FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, true},
   292  			// from block "higher" than to block
   293  			{FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(1)}, false},
   294  			// from block "higher" than to block
   295  			{FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false},
   296  			// from block "higher" than to block
   297  			{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false},
   298  			// from block "higher" than to block
   299  			{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false},
   300  		}
   301  	)
   302  
   303  	for i, test := range testCases {
   304  		_, err := api.NewFilter(test.crit)
   305  		if test.success && err != nil {
   306  			t.Errorf("expected filter creation for case %d to success, got %v", i, err)
   307  		}
   308  		if !test.success && err == nil {
   309  			t.Errorf("expected testcase %d to fail with an error", i)
   310  		}
   311  	}
   312  }
   313  
   314  // TestInvalidLogFilterCreation tests whether invalid filter log criteria results in an error
   315  // when the filter is created.
   316  func TestInvalidLogFilterCreation(t *testing.T) {
   317  	t.Parallel()
   318  
   319  	var (
   320  		db      = rawdb.NewMemoryDatabase()
   321  		backend = &testBackend{db: db}
   322  		api     = NewPublicFilterAPI(backend, false, deadline)
   323  	)
   324  
   325  	// different situations where log filter creation should fail.
   326  	// Reason: fromBlock > toBlock
   327  	testCases := []FilterCriteria{
   328  		0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
   329  		1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)},
   330  		2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)},
   331  	}
   332  
   333  	for i, test := range testCases {
   334  		if _, err := api.NewFilter(test); err == nil {
   335  			t.Errorf("Expected NewFilter for case #%d to fail", i)
   336  		}
   337  	}
   338  }
   339  
   340  func TestInvalidGetLogsRequest(t *testing.T) {
   341  	var (
   342  		db        = rawdb.NewMemoryDatabase()
   343  		backend   = &testBackend{db: db}
   344  		api       = NewPublicFilterAPI(backend, false, deadline)
   345  		blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
   346  	)
   347  
   348  	// Reason: Cannot specify both BlockHash and FromBlock/ToBlock)
   349  	testCases := []FilterCriteria{
   350  		0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
   351  		1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
   352  		2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
   353  	}
   354  
   355  	for i, test := range testCases {
   356  		if _, err := api.GetLogs(context.Background(), test); err == nil {
   357  			t.Errorf("Expected Logs for case #%d to fail", i)
   358  		}
   359  	}
   360  }
   361  
   362  // TestLogFilter tests whether log filters match the correct logs that are posted to the event feed.
   363  func TestLogFilter(t *testing.T) {
   364  	t.Parallel()
   365  
   366  	var (
   367  		db      = rawdb.NewMemoryDatabase()
   368  		backend = &testBackend{db: db}
   369  		api     = NewPublicFilterAPI(backend, false, deadline)
   370  
   371  		firstAddr      = common.HexToAddress("0x1111111111111111111111111111111111111111")
   372  		secondAddr     = common.HexToAddress("0x2222222222222222222222222222222222222222")
   373  		thirdAddress   = common.HexToAddress("0x3333333333333333333333333333333333333333")
   374  		notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999")
   375  		firstTopic     = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
   376  		secondTopic    = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222")
   377  		notUsedTopic   = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999")
   378  
   379  		// posted twice, once as regular logs and once as pending logs.
   380  		allLogs = []*types.Log{
   381  			{Address: firstAddr},
   382  			{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1},
   383  			{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1},
   384  			{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2},
   385  			{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3},
   386  		}
   387  
   388  		expectedCase7  = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]}
   389  		expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]}
   390  
   391  		testCases = []struct {
   392  			crit     FilterCriteria
   393  			expected []*types.Log
   394  			id       rpc.ID
   395  		}{
   396  			// match all
   397  			0: {FilterCriteria{}, allLogs, ""},
   398  			// match none due to no matching addresses
   399  			1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}}, []*types.Log{}, ""},
   400  			// match logs based on addresses, ignore topics
   401  			2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""},
   402  			// match none due to no matching topics (match with address)
   403  			3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""},
   404  			// match logs based on addresses and topics
   405  			4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""},
   406  			// match logs based on multiple addresses and "or" topics
   407  			5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""},
   408  			// logs in the pending block
   409  			6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""},
   410  			// mined logs with block num >= 2 or pending logs
   411  			7: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, expectedCase7, ""},
   412  			// all "mined" logs with block num >= 2
   413  			8: {FilterCriteria{FromBlock: big.NewInt(2), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs[3:], ""},
   414  			// all "mined" logs
   415  			9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""},
   416  			// all "mined" logs with 1>= block num <=2 and topic secondTopic
   417  			10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""},
   418  			// all "mined" and pending logs with topic firstTopic
   419  			11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""},
   420  			// match all logs due to wildcard topic
   421  			12: {FilterCriteria{Topics: [][]common.Hash{nil}}, allLogs[1:], ""},
   422  		}
   423  	)
   424  
   425  	// create all filters
   426  	for i := range testCases {
   427  		testCases[i].id, _ = api.NewFilter(testCases[i].crit)
   428  	}
   429  
   430  	// raise events
   431  	time.Sleep(1 * time.Second)
   432  	if nsend := backend.logsFeed.Send(allLogs); nsend == 0 {
   433  		t.Fatal("Logs event not delivered")
   434  	}
   435  	if nsend := backend.pendingLogsFeed.Send(allLogs); nsend == 0 {
   436  		t.Fatal("Pending logs event not delivered")
   437  	}
   438  
   439  	for i, tt := range testCases {
   440  		var fetched []*types.Log
   441  		timeout := time.Now().Add(1 * time.Second)
   442  		for { // fetch all expected logs
   443  			results, err := api.GetFilterChanges(tt.id)
   444  			if err != nil {
   445  				t.Fatalf("Unable to fetch logs: %v", err)
   446  			}
   447  
   448  			fetched = append(fetched, results.([]*types.Log)...)
   449  			if len(fetched) >= len(tt.expected) {
   450  				break
   451  			}
   452  			// check timeout
   453  			if time.Now().After(timeout) {
   454  				break
   455  			}
   456  
   457  			time.Sleep(100 * time.Millisecond)
   458  		}
   459  
   460  		if len(fetched) != len(tt.expected) {
   461  			t.Errorf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched))
   462  			return
   463  		}
   464  
   465  		for l := range fetched {
   466  			if fetched[l].Removed {
   467  				t.Errorf("expected log not to be removed for log %d in case %d", l, i)
   468  			}
   469  			if !reflect.DeepEqual(fetched[l], tt.expected[l]) {
   470  				t.Errorf("invalid log on index %d for case %d", l, i)
   471  			}
   472  		}
   473  	}
   474  }
   475  
   476  // TestPendingLogsSubscription tests if a subscription receives the correct pending logs that are posted to the event feed.
   477  func TestPendingLogsSubscription(t *testing.T) {
   478  	t.Parallel()
   479  
   480  	var (
   481  		db      = rawdb.NewMemoryDatabase()
   482  		backend = &testBackend{db: db}
   483  		api     = NewPublicFilterAPI(backend, false, deadline)
   484  
   485  		firstAddr      = common.HexToAddress("0x1111111111111111111111111111111111111111")
   486  		secondAddr     = common.HexToAddress("0x2222222222222222222222222222222222222222")
   487  		thirdAddress   = common.HexToAddress("0x3333333333333333333333333333333333333333")
   488  		notUsedAddress = common.HexToAddress("0x9999999999999999999999999999999999999999")
   489  		firstTopic     = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
   490  		secondTopic    = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222")
   491  		thirdTopic     = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333")
   492  		fourthTopic    = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444")
   493  		notUsedTopic   = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999")
   494  
   495  		allLogs = [][]*types.Log{
   496  			{{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}},
   497  			{{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}},
   498  			{{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}},
   499  			{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}},
   500  			{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}},
   501  			{
   502  				{Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5},
   503  				{Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5},
   504  				{Address: thirdAddress, Topics: []common.Hash{fourthTopic}, BlockNumber: 5},
   505  				{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5},
   506  			},
   507  		}
   508  
   509  		testCases = []struct {
   510  			crit     quai.FilterQuery
   511  			expected []*types.Log
   512  			c        chan []*types.Log
   513  			sub      *Subscription
   514  		}{
   515  			// match all
   516  			{
   517  				quai.FilterQuery{}, flattenLogs(allLogs),
   518  				nil, nil,
   519  			},
   520  			// match none due to no matching addresses
   521  			{
   522  				quai.FilterQuery{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{nil}},
   523  				nil,
   524  				nil, nil,
   525  			},
   526  			// match logs based on addresses, ignore topics
   527  			{
   528  				quai.FilterQuery{Addresses: []common.Address{firstAddr}},
   529  				append(flattenLogs(allLogs[:2]), allLogs[5][3]),
   530  				nil, nil,
   531  			},
   532  			// match none due to no matching topics (match with address)
   533  			{
   534  				quai.FilterQuery{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}},
   535  				nil, nil, nil,
   536  			},
   537  			// match logs based on addresses and topics
   538  			{
   539  				quai.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}},
   540  				append(flattenLogs(allLogs[3:5]), allLogs[5][0]),
   541  				nil, nil,
   542  			},
   543  			// match logs based on multiple addresses and "or" topics
   544  			{
   545  				quai.FilterQuery{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}},
   546  				append(flattenLogs(allLogs[2:5]), allLogs[5][0]),
   547  				nil,
   548  				nil,
   549  			},
   550  			// block numbers are ignored for filters created with New***Filter, these return all logs that match the given criteria when the state changes
   551  			{
   552  				quai.FilterQuery{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(2), ToBlock: big.NewInt(3)},
   553  				append(flattenLogs(allLogs[:2]), allLogs[5][3]),
   554  				nil, nil,
   555  			},
   556  			// multiple pending logs, should match only 2 topics from the logs in block 5
   557  			{
   558  				quai.FilterQuery{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, fourthTopic}}},
   559  				[]*types.Log{allLogs[5][0], allLogs[5][2]},
   560  				nil, nil,
   561  			},
   562  		}
   563  	)
   564  
   565  	// create all subscriptions, this ensures all subscriptions are created before the events are posted.
   566  	// on slow machines this could otherwise lead to missing events when the subscription is created after
   567  	// (some) events are posted.
   568  	for i := range testCases {
   569  		testCases[i].c = make(chan []*types.Log)
   570  		testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c)
   571  	}
   572  
   573  	for n, test := range testCases {
   574  		i := n
   575  		tt := test
   576  		go func() {
   577  			var fetched []*types.Log
   578  		fetchLoop:
   579  			for {
   580  				logs := <-tt.c
   581  				fetched = append(fetched, logs...)
   582  				if len(fetched) >= len(tt.expected) {
   583  					break fetchLoop
   584  				}
   585  			}
   586  
   587  			if len(fetched) != len(tt.expected) {
   588  				panic(fmt.Sprintf("invalid number of logs for case %d, want %d log(s), got %d", i, len(tt.expected), len(fetched)))
   589  			}
   590  
   591  			for l := range fetched {
   592  				if fetched[l].Removed {
   593  					panic(fmt.Sprintf("expected log not to be removed for log %d in case %d", l, i))
   594  				}
   595  				if !reflect.DeepEqual(fetched[l], tt.expected[l]) {
   596  					panic(fmt.Sprintf("invalid log on index %d for case %d", l, i))
   597  				}
   598  			}
   599  		}()
   600  	}
   601  
   602  	// raise events
   603  	time.Sleep(1 * time.Second)
   604  	for _, ev := range allLogs {
   605  		backend.pendingLogsFeed.Send(ev)
   606  	}
   607  }
   608  
   609  // TestPendingTxFilterDeadlock tests if the event loop hangs when pending
   610  // txes arrive at the same time that one of multiple filters is timing out.
   611  // Please refer to #22131 for more details.
   612  func TestPendingTxFilterDeadlock(t *testing.T) {
   613  	t.Parallel()
   614  	timeout := 100 * time.Millisecond
   615  
   616  	var (
   617  		db      = rawdb.NewMemoryDatabase()
   618  		backend = &testBackend{db: db}
   619  		api     = NewPublicFilterAPI(backend, false, timeout)
   620  		done    = make(chan struct{})
   621  	)
   622  
   623  	go func() {
   624  		// Bombard feed with txes until signal was received to stop
   625  		i := uint64(0)
   626  		for {
   627  			select {
   628  			case <-done:
   629  				return
   630  			default:
   631  			}
   632  
   633  			tx := types.NewTransaction(i, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil)
   634  			backend.txFeed.Send(core.NewTxsEvent{Txs: []*types.Transaction{tx}})
   635  			i++
   636  		}
   637  	}()
   638  
   639  	// Create a bunch of filters that will
   640  	// timeout either in 100ms or 200ms
   641  	fids := make([]rpc.ID, 20)
   642  	for i := 0; i < len(fids); i++ {
   643  		fid := api.NewPendingTransactionFilter()
   644  		fids[i] = fid
   645  		// Wait for at least one tx to arrive in filter
   646  		for {
   647  			hashes, err := api.GetFilterChanges(fid)
   648  			if err != nil {
   649  				t.Fatalf("Filter should exist: %v\n", err)
   650  			}
   651  			if len(hashes.([]common.Hash)) > 0 {
   652  				break
   653  			}
   654  			runtime.Gosched()
   655  		}
   656  	}
   657  
   658  	// Wait until filters have timed out
   659  	time.Sleep(3 * timeout)
   660  
   661  	// If tx loop doesn't consume `done` after a second
   662  	// it's hanging.
   663  	select {
   664  	case done <- struct{}{}:
   665  		// Check that all filters have been uninstalled
   666  		for _, fid := range fids {
   667  			if _, err := api.GetFilterChanges(fid); err == nil {
   668  				t.Errorf("Filter %s should have been uninstalled\n", fid)
   669  			}
   670  		}
   671  	case <-time.After(1 * time.Second):
   672  		t.Error("Tx sending loop hangs")
   673  	}
   674  }
   675  
   676  func flattenLogs(pl [][]*types.Log) []*types.Log {
   677  	var logs []*types.Log
   678  	for _, l := range pl {
   679  		logs = append(logs, l...)
   680  	}
   681  	return logs
   682  }