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 }