github.com/klaytn/klaytn@v1.12.1/blockchain/blockchain_kes_test.go (about)

     1  // Copyright 2020 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package blockchain
    18  
    19  import (
    20  	"os"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/golang/mock/gomock"
    25  	"github.com/influxdata/influxdb/pkg/deep"
    26  	"github.com/klaytn/klaytn/blockchain/state"
    27  	"github.com/klaytn/klaytn/blockchain/types"
    28  	"github.com/klaytn/klaytn/common"
    29  	"github.com/klaytn/klaytn/common/hexutil"
    30  	"github.com/klaytn/klaytn/rlp"
    31  	"github.com/klaytn/klaytn/storage/database"
    32  	mock_statedb "github.com/klaytn/klaytn/storage/statedb/mocks"
    33  )
    34  
    35  func getTestBlock(t *testing.T) types.Block {
    36  	var block types.Block
    37  	blockDump, err := os.ReadFile("../tests/b1.rlp")
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	if err := rlp.DecodeBytes(common.FromHex(string(blockDump)), &block); err != nil {
    42  		t.Fatal("decode error: ", err)
    43  	}
    44  	return block
    45  }
    46  
    47  func getTestLogs(t *testing.T) ([]*types.Receipt, []*types.LogForStorage, []byte) {
    48  	testReceipts := []*types.Receipt{
    49  		{
    50  			Logs: []*types.Log{
    51  				{
    52  					Address:     common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
    53  					BlockHash:   common.HexToHash("0x1430cbc43787f54eb0b77dfd4de8246a8c256aeac79c1e0c94dc7c59ba4e7c57"),
    54  					BlockNumber: 1,
    55  					Data:        hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"),
    56  					Index:       0,
    57  					TxIndex:     0,
    58  					TxHash:      common.HexToHash("0x7bea0019816d8146eec8cebd7dea862aa6e97fb5387c354f7d484e1d1e79efec"),
    59  					Topics: []common.Hash{
    60  						common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
    61  						common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
    62  					},
    63  				},
    64  			},
    65  		},
    66  		{
    67  			Logs: []*types.Log{
    68  				{
    69  					Address:     common.HexToAddress("0x91d6f7d2537d8a0bd7d487dcc59151ebc00da306"),
    70  					BlockHash:   common.HexToHash("0x1430cbc43787f54eb0b77dfd4de8246a8c256aeac79c1e0c94dc7c59ba4e7c57"),
    71  					BlockNumber: 1,
    72  					Data:        []byte{},
    73  					Index:       1,
    74  					TxIndex:     3,
    75  					TxHash:      common.HexToHash("0xb8e08da739c350f7e11e392cbac5b48d992e91990b643726be6c8ccf12a07e2b"),
    76  					Topics: []common.Hash{
    77  						common.HexToHash("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace113"),
    78  						common.HexToHash("0x84d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace243"),
    79  					},
    80  				},
    81  			},
    82  		},
    83  	}
    84  
    85  	testStorageLogs := []*types.LogForStorage{}
    86  	for _, receipts := range testReceipts {
    87  		for _, log := range receipts.Logs {
    88  			testStorageLogs = append(testStorageLogs, (*types.LogForStorage)(log))
    89  		}
    90  	}
    91  
    92  	encodedBlockLogs, err := rlp.EncodeToBytes(testStorageLogs)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	return testReceipts, testStorageLogs, encodedBlockLogs
    97  }
    98  
    99  func TestBlockChain_sendKESSubscriptionData(t *testing.T) {
   100  	mockCtrl := gomock.NewController(t)
   101  	defer mockCtrl.Finish()
   102  	mockTrieNodeCache := mock_statedb.NewMockTrieNodeCache(mockCtrl)
   103  
   104  	chainCh := make(chan ChainEvent)
   105  	logsCh := make(chan []*types.Log)
   106  	defer close(chainCh)
   107  	defer close(logsCh)
   108  
   109  	// prepare Blockchain to be tested
   110  	bc := BlockChain{stateCache: state.NewDatabaseWithExistingCache(database.NewMemoryDBManager(), mockTrieNodeCache)}
   111  	bc.SubscribeChainEvent(chainCh)
   112  	bc.SubscribeLogsEvent(logsCh)
   113  
   114  	// prepare test data to be send by sendKESSubscriptionData
   115  	block := getTestBlock(t)
   116  	blockLogsKey := append(kesCachePrefixBlockLogs, block.Number().Bytes()...)
   117  	receipts, blockLogs, encodedBlockLogs := getTestLogs(t)
   118  
   119  	// resultCh receive data when checkSubscribedData finished successfully
   120  	resultCh := make(chan struct{})
   121  	defer close(resultCh)
   122  
   123  	// check whether expected data are delivered to the subscription channel
   124  	checkSubscribedData := func() {
   125  		subscribedChain := <-chainCh
   126  		if block.Hash() != subscribedChain.Block.Hash() ||
   127  			!deep.Equal(block.Header(), subscribedChain.Block.Header()) ||
   128  			!deep.Equal(block.Transactions(), subscribedChain.Block.Transactions()) {
   129  			t.Errorf("\nexpected block=%v\nactual block=%v", block.String(), subscribedChain.Block.String())
   130  			// to terminate blocking main thread
   131  			panic("block doesn't match")
   132  		}
   133  
   134  		subscribedLogs := <-logsCh
   135  		if len(subscribedLogs) != len(blockLogs) {
   136  			t.Errorf("expected length=%d, actual length=%d", len(blockLogs), len(subscribedLogs))
   137  			// to terminate blocking main thread
   138  			panic("log length doesn't match")
   139  		}
   140  
   141  		for i, testLog := range blockLogs {
   142  			expectedLog := (*types.Log)(testLog)
   143  			if !deep.Equal(expectedLog, subscribedLogs[i]) {
   144  				t.Errorf("%dth log doen't match\nexpected log=%v\nactual log=%v",
   145  					i, expectedLog.String(), subscribedLogs[i].String())
   146  				// to terminate blocking main thread
   147  				panic("log doesn't match")
   148  			}
   149  		}
   150  		resultCh <- struct{}{}
   151  	}
   152  
   153  	// in normal case, block logs are retrieved by remote cache
   154  	{
   155  		mockTrieNodeCache.EXPECT().Get(blockLogsKey).Return(encodedBlockLogs).Times(1)
   156  		bc.db = nil
   157  
   158  		go checkSubscribedData()
   159  		bc.sendKESSubscriptionData(&block)
   160  
   161  		select {
   162  		case <-resultCh:
   163  		case <-time.NewTimer(100 * time.Millisecond).C:
   164  			t.Fatal("timeout")
   165  		}
   166  	}
   167  
   168  	// if remote cache has invalid block logs, block logs are retrieved by database
   169  	{
   170  		mockTrieNodeCache.EXPECT().Get(blockLogsKey).Return([]byte{0x1, 0x2}).Times(1)
   171  		bc.db = database.NewMemoryDBManager()
   172  		bc.db.WriteReceipts(block.Hash(), block.NumberU64(), receipts)
   173  
   174  		go checkSubscribedData()
   175  		bc.sendKESSubscriptionData(&block)
   176  
   177  		select {
   178  		case <-resultCh:
   179  		case <-time.NewTimer(100 * time.Millisecond).C:
   180  			t.Fatal("timeout")
   181  		}
   182  	}
   183  
   184  	// if remote cache doesn't have block logs, block logs are retrieved by database
   185  	{
   186  		mockTrieNodeCache.EXPECT().Get(blockLogsKey).Return(nil).Times(1)
   187  		bc.db = database.NewMemoryDBManager()
   188  		bc.db.WriteReceipts(block.Hash(), block.NumberU64(), receipts)
   189  
   190  		go checkSubscribedData()
   191  		bc.sendKESSubscriptionData(&block)
   192  
   193  		select {
   194  		case <-resultCh:
   195  		case <-time.NewTimer(100 * time.Millisecond).C:
   196  			t.Fatal("timeout")
   197  		}
   198  	}
   199  }