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  }