github.com/klaytn/klaytn@v1.12.1/node/cn/filters/filter_test.go (about)

     1  // Modifications Copyright 2019 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from eth/filters/filter_system_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package filters
    22  
    23  import (
    24  	"context"
    25  	"math/big"
    26  	"testing"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/klaytn/klaytn/blockchain"
    30  	"github.com/klaytn/klaytn/blockchain/types"
    31  	"github.com/klaytn/klaytn/common"
    32  	"github.com/klaytn/klaytn/consensus/gxhash"
    33  	"github.com/klaytn/klaytn/crypto"
    34  	"github.com/klaytn/klaytn/event"
    35  	"github.com/klaytn/klaytn/networks/rpc"
    36  	cn "github.com/klaytn/klaytn/node/cn/filters/mock"
    37  	"github.com/klaytn/klaytn/params"
    38  	"github.com/klaytn/klaytn/storage/database"
    39  	"github.com/pkg/errors"
    40  	"github.com/stretchr/testify/assert"
    41  )
    42  
    43  var (
    44  	addr1 = common.HexToAddress("111")
    45  	addr2 = common.HexToAddress("222")
    46  	addrs []common.Address
    47  )
    48  
    49  var (
    50  	topic1 common.Hash
    51  	topic2 common.Hash
    52  	topics [][]common.Hash
    53  )
    54  
    55  var (
    56  	begin = int64(12345)
    57  	end   = int64(12345)
    58  )
    59  
    60  var header *types.Header
    61  
    62  var someErr = errors.New("some error")
    63  
    64  func init() {
    65  	addrs = []common.Address{addr1, addr2}
    66  	topics = [][]common.Hash{{topic1}, {topic2}}
    67  	header = &types.Header{
    68  		Number:     big.NewInt(int64(123)),
    69  		BlockScore: big.NewInt(int64(1)),
    70  		Extra:      addrs[0][:],
    71  		Governance: addrs[0][:],
    72  		Vote:       addrs[0][:],
    73  	}
    74  }
    75  
    76  func genFilter(t *testing.T) (*gomock.Controller, *cn.MockBackend, *Filter) {
    77  	mockCtrl := gomock.NewController(t)
    78  	mockBackend := cn.NewMockBackend(mockCtrl)
    79  	mockBackend.EXPECT().BloomStatus().Return(uint64(123), uint64(321)).Times(1)
    80  	newFilter := NewRangeFilter(mockBackend, begin, end, addrs, topics)
    81  	return mockCtrl, mockBackend, newFilter
    82  }
    83  
    84  func TestFilter_New(t *testing.T) {
    85  	mockCtrl, mockBackend, newFilter := genFilter(t)
    86  	defer mockCtrl.Finish()
    87  
    88  	assert.NotNil(t, newFilter)
    89  	assert.Equal(t, mockBackend, newFilter.backend)
    90  	assert.Equal(t, begin, newFilter.begin)
    91  	assert.Equal(t, end, newFilter.end)
    92  	assert.Equal(t, topics, newFilter.topics)
    93  	assert.Equal(t, addrs, newFilter.addresses)
    94  	assert.NotNil(t, newFilter.matcher)
    95  }
    96  
    97  func TestFilter_Logs(t *testing.T) {
    98  	ctx := context.Background()
    99  	{
   100  		mockCtrl, mockBackend, newFilter := genFilter(t)
   101  		mockBackend.EXPECT().HeaderByNumber(ctx, rpc.LatestBlockNumber).Times(1).Return(nil, nil)
   102  		logs, err := newFilter.Logs(ctx)
   103  		assert.Nil(t, logs)
   104  		assert.NoError(t, err)
   105  		mockCtrl.Finish()
   106  	}
   107  }
   108  
   109  func TestFilter_unindexedLogs(t *testing.T) {
   110  	ctx := context.Background()
   111  	{
   112  		mockCtrl, mockBackend, newFilter := genFilter(t)
   113  		mockBackend.EXPECT().HeaderByNumber(ctx, rpc.BlockNumber(newFilter.begin)).Times(1).Return(nil, nil)
   114  		logs, err := newFilter.unindexedLogs(ctx, uint64(newFilter.end))
   115  		assert.Nil(t, logs)
   116  		assert.NoError(t, err)
   117  		mockCtrl.Finish()
   118  	}
   119  	{
   120  		mockCtrl, mockBackend, newFilter := genFilter(t)
   121  		mockBackend.EXPECT().HeaderByNumber(ctx, rpc.BlockNumber(newFilter.begin)).Times(1).Return(header, nil)
   122  		logs, err := newFilter.unindexedLogs(ctx, uint64(newFilter.end))
   123  		assert.Nil(t, logs)
   124  		assert.NoError(t, err)
   125  		mockCtrl.Finish()
   126  	}
   127  }
   128  
   129  func TestFilter_checkMatches(t *testing.T) {
   130  	ctx := context.Background()
   131  	{
   132  		mockCtrl, mockBackend, newFilter := genFilter(t)
   133  		mockBackend.EXPECT().GetLogs(ctx, header.Hash()).Times(1).Return(nil, someErr)
   134  		logs, err := newFilter.checkMatches(ctx, header)
   135  		assert.Nil(t, logs)
   136  		assert.Equal(t, someErr, err)
   137  		mockCtrl.Finish()
   138  	}
   139  	{
   140  		mockCtrl, mockBackend, newFilter := genFilter(t)
   141  		mockBackend.EXPECT().GetLogs(ctx, header.Hash()).Times(1).Return(nil, nil)
   142  		logs, err := newFilter.checkMatches(ctx, header)
   143  		assert.Nil(t, logs)
   144  		assert.NoError(t, err)
   145  		mockCtrl.Finish()
   146  	}
   147  }
   148  
   149  func TestFilter_bloomFilter(t *testing.T) {
   150  	{
   151  		assert.True(t, bloomFilter(types.Bloom{}, nil, nil))
   152  	}
   153  	{
   154  		assert.False(t, bloomFilter(types.Bloom{}, nil, [][]common.Hash{{topic1}}))
   155  	}
   156  	{
   157  		assert.False(t, bloomFilter(types.Bloom{}, []common.Address{addr1}, nil))
   158  	}
   159  }
   160  
   161  func makeReceipt(addr common.Address) *types.Receipt {
   162  	receipt := genReceipt(false, 0)
   163  	receipt.Logs = []*types.Log{
   164  		{Address: addr},
   165  	}
   166  	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   167  	return receipt
   168  }
   169  
   170  func BenchmarkFilters(b *testing.B) {
   171  	var (
   172  		db         = database.NewMemoryDBManager()
   173  		mux        = new(event.TypeMux)
   174  		txFeed     = new(event.Feed)
   175  		rmLogsFeed = new(event.Feed)
   176  		logsFeed   = new(event.Feed)
   177  		chainFeed  = new(event.Feed)
   178  		backend    = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed, params.TestChainConfig}
   179  		key1, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   180  		addr1      = crypto.PubkeyToAddress(key1.PublicKey)
   181  		addr2      = common.BytesToAddress([]byte("jeff"))
   182  		addr3      = common.BytesToAddress([]byte("ethereum"))
   183  		addr4      = common.BytesToAddress([]byte("random addresses please"))
   184  	)
   185  	defer db.Close()
   186  
   187  	genesis := blockchain.GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
   188  	chain, receipts := blockchain.GenerateChain(params.TestChainConfig, genesis, gxhash.NewFaker(), db, 100010, func(i int, gen *blockchain.BlockGen) {
   189  		switch i {
   190  		case 2403:
   191  			receipt := makeReceipt(addr1)
   192  			gen.AddUncheckedReceipt(receipt)
   193  		case 1034:
   194  			receipt := makeReceipt(addr2)
   195  			gen.AddUncheckedReceipt(receipt)
   196  		case 34:
   197  			receipt := makeReceipt(addr3)
   198  			gen.AddUncheckedReceipt(receipt)
   199  		case 99999:
   200  			receipt := makeReceipt(addr4)
   201  			gen.AddUncheckedReceipt(receipt)
   202  
   203  		}
   204  	})
   205  	for i, block := range chain {
   206  		db.WriteBlock(block)
   207  		db.WriteCanonicalHash(block.Hash(), block.NumberU64())
   208  		db.WriteHeadBlockHash(block.Hash())
   209  		db.WriteReceipts(block.Hash(), block.NumberU64(), receipts[i])
   210  	}
   211  	b.ResetTimer()
   212  
   213  	filter := NewRangeFilter(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil)
   214  
   215  	for i := 0; i < b.N; i++ {
   216  		logs, _ := filter.Logs(context.Background())
   217  		if len(logs) != 4 {
   218  			b.Fatal("expected 4 logs, got", len(logs))
   219  		}
   220  	}
   221  }
   222  
   223  func genReceipt(failed bool, cumulativeGasUsed uint64) *types.Receipt {
   224  	r := &types.Receipt{GasUsed: cumulativeGasUsed}
   225  	if failed {
   226  		r.Status = types.ReceiptStatusFailed
   227  	} else {
   228  		r.Status = types.ReceiptStatusSuccessful
   229  	}
   230  	return r
   231  }
   232  
   233  func TestFilters(t *testing.T) {
   234  	var (
   235  		db         = database.NewMemoryDBManager()
   236  		mux        = new(event.TypeMux)
   237  		txFeed     = new(event.Feed)
   238  		rmLogsFeed = new(event.Feed)
   239  		logsFeed   = new(event.Feed)
   240  		chainFeed  = new(event.Feed)
   241  		backend    = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed, params.TestChainConfig}
   242  		key1, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   243  		addr       = crypto.PubkeyToAddress(key1.PublicKey)
   244  
   245  		hash1 = common.BytesToHash([]byte("topic1"))
   246  		hash2 = common.BytesToHash([]byte("topic2"))
   247  		hash3 = common.BytesToHash([]byte("topic3"))
   248  		hash4 = common.BytesToHash([]byte("topic4"))
   249  	)
   250  	defer db.Close()
   251  
   252  	genesis := blockchain.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
   253  	chain, receipts := blockchain.GenerateChain(params.TestChainConfig, genesis, gxhash.NewFaker(), db, 1000, func(i int, gen *blockchain.BlockGen) {
   254  		switch i {
   255  		case 1:
   256  			receipt := genReceipt(false, 0)
   257  			receipt.Logs = []*types.Log{
   258  				{
   259  					Address: addr,
   260  					Topics:  []common.Hash{hash1},
   261  				},
   262  			}
   263  			gen.AddUncheckedReceipt(receipt)
   264  			gen.AddUncheckedTx(types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil))
   265  		case 2:
   266  			receipt := genReceipt(false, 0)
   267  			receipt.Logs = []*types.Log{
   268  				{
   269  					Address: addr,
   270  					Topics:  []common.Hash{hash2},
   271  				},
   272  			}
   273  			gen.AddUncheckedReceipt(receipt)
   274  			gen.AddUncheckedTx(types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil))
   275  
   276  		case 998:
   277  			receipt := genReceipt(false, 0)
   278  			receipt.Logs = []*types.Log{
   279  				{
   280  					Address: addr,
   281  					Topics:  []common.Hash{hash3},
   282  				},
   283  			}
   284  			gen.AddUncheckedReceipt(receipt)
   285  			gen.AddUncheckedTx(types.NewTransaction(998, common.HexToAddress("0x998"), big.NewInt(998), 998, big.NewInt(998), nil))
   286  		case 999:
   287  			receipt := genReceipt(false, 0)
   288  			receipt.Logs = []*types.Log{
   289  				{
   290  					Address: addr,
   291  					Topics:  []common.Hash{hash4},
   292  				},
   293  			}
   294  			gen.AddUncheckedReceipt(receipt)
   295  			gen.AddUncheckedTx(types.NewTransaction(999, common.HexToAddress("0x999"), big.NewInt(999), 999, big.NewInt(999), nil))
   296  		}
   297  	})
   298  	for i, block := range chain {
   299  		db.WriteBlock(block)
   300  		db.WriteCanonicalHash(block.Hash(), block.NumberU64())
   301  		db.WriteHeadBlockHash(block.Hash())
   302  		db.WriteReceipts(block.Hash(), block.NumberU64(), receipts[i])
   303  	}
   304  
   305  	filter := NewRangeFilter(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
   306  
   307  	logs, _ := filter.Logs(context.Background())
   308  	if len(logs) != 4 {
   309  		t.Error("expected 4 log, got", len(logs))
   310  	}
   311  
   312  	filter = NewRangeFilter(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
   313  	logs, _ = filter.Logs(context.Background())
   314  	if len(logs) != 1 {
   315  		t.Error("expected 1 log, got", len(logs))
   316  	}
   317  	if len(logs) > 0 && logs[0].Topics[0] != hash3 {
   318  		t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
   319  	}
   320  
   321  	filter = NewRangeFilter(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
   322  	logs, _ = filter.Logs(context.Background())
   323  	if len(logs) != 1 {
   324  		t.Error("expected 1 log, got", len(logs))
   325  	}
   326  	if len(logs) > 0 && logs[0].Topics[0] != hash3 {
   327  		t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
   328  	}
   329  
   330  	filter = NewRangeFilter(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}})
   331  
   332  	logs, _ = filter.Logs(context.Background())
   333  	if len(logs) != 2 {
   334  		t.Error("expected 2 log, got", len(logs))
   335  	}
   336  
   337  	failHash := common.BytesToHash([]byte("fail"))
   338  	filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}})
   339  
   340  	logs, _ = filter.Logs(context.Background())
   341  	if len(logs) != 0 {
   342  		t.Error("expected 0 log, got", len(logs))
   343  	}
   344  
   345  	failAddr := common.BytesToAddress([]byte("failmenow"))
   346  	filter = NewRangeFilter(backend, 0, -1, []common.Address{failAddr}, nil)
   347  
   348  	logs, _ = filter.Logs(context.Background())
   349  	if len(logs) != 0 {
   350  		t.Error("expected 0 log, got", len(logs))
   351  	}
   352  
   353  	filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
   354  
   355  	logs, _ = filter.Logs(context.Background())
   356  	if len(logs) != 0 {
   357  		t.Error("expected 0 log, got", len(logs))
   358  	}
   359  }