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