github.com/klaytn/klaytn@v1.10.2/tests/db_write_and_read_test.go (about) 1 // Copyright 2019 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 tests 18 19 import ( 20 "io/ioutil" 21 "math/big" 22 "os" 23 "strconv" 24 "testing" 25 26 "github.com/klaytn/klaytn/blockchain" 27 "github.com/klaytn/klaytn/blockchain/types" 28 "github.com/klaytn/klaytn/common" 29 "github.com/klaytn/klaytn/crypto" 30 "github.com/klaytn/klaytn/params" 31 "github.com/klaytn/klaytn/storage/database" 32 "github.com/stretchr/testify/assert" 33 ) 34 35 type testEntry struct { 36 name string 37 dbConfig *database.DBConfig 38 } 39 40 var testEntries = []testEntry{ 41 {"BadgerDB-Single", &database.DBConfig{DBType: database.BadgerDB, SingleDB: true}}, 42 {"BadgerDB", &database.DBConfig{DBType: database.BadgerDB, SingleDB: false, NumStateTrieShards: 4}}, 43 {"MemoryDB-Single", &database.DBConfig{DBType: database.MemoryDB, SingleDB: true}}, 44 {"MemoryDB", &database.DBConfig{DBType: database.MemoryDB, SingleDB: false, NumStateTrieShards: 4}}, 45 {"LevelDB-Single", &database.DBConfig{DBType: database.LevelDB, SingleDB: true, LevelDBCacheSize: 128, OpenFilesLimit: 32}}, 46 {"LevelDB", &database.DBConfig{DBType: database.LevelDB, SingleDB: false, LevelDBCacheSize: 128, OpenFilesLimit: 32, NumStateTrieShards: 4}}, 47 } 48 49 // TestDBManager_WriteAndRead_Functional checks basic functionality of database.DBManager interface 50 // with underlying Database with combination of various configurations. Test cases usually include 51 // 1) read before write, 2) read after write, 3) read after overwrite and 4) read after delete. 52 // Sometimes 3) and 4) are omitted if such operation is not possible due to some reasons. 53 func TestDBManager_WriteAndRead_Functional(t *testing.T) { 54 for _, entry := range testEntries { 55 tempDir, err := ioutil.TempDir("", "klaytn-db-manager-test") 56 if err != nil { 57 t.Fatalf("cannot create temporary directory: %v", err) 58 } 59 entry.dbConfig.Dir = tempDir 60 dbManager := database.NewDBManager(entry.dbConfig) 61 62 t.Run(entry.name, func(t *testing.T) { 63 testWriteAndReadCanonicalHash(t, dbManager) 64 testWriteAndReadHeaderHash(t, dbManager) 65 testWriteAndReadBlockHash(t, dbManager) 66 testWriteAndReadFastBlockHash(t, dbManager) 67 testWriteAndReadFastTrieProgress(t, dbManager) 68 testWriteAndReadHeader(t, dbManager) 69 testWriteAndReadBody(t, dbManager) 70 testWriteAndReadTd(t, dbManager) 71 testWriteAndReadReceipts(t, dbManager) 72 testWriteAndReadBlock(t, dbManager) 73 // TODO-Klaytn-Storage To implement this test case, error shouldn't be returned. 74 // testWriteAndReadIstanbulSnapshot(t, dbManager) 75 }) 76 77 dbManager.Close() 78 os.RemoveAll(tempDir) 79 } 80 } 81 82 func testWriteAndReadCanonicalHash(t *testing.T, dbManager database.DBManager) { 83 hash1 := common.HexToHash("111") 84 hash2 := common.HexToHash("222") 85 86 // 1. Before write, empty hash should be returned. 87 assert.Equal(t, common.Hash{}, dbManager.ReadCanonicalHash(111)) 88 89 // 2. After write, written hash should be returned. 90 dbManager.WriteCanonicalHash(hash1, 111) 91 assert.Equal(t, hash1, dbManager.ReadCanonicalHash(111)) 92 93 // 3. After overwrite, overwritten hash should be returned. 94 dbManager.WriteCanonicalHash(hash2, 111) 95 assert.Equal(t, hash2, dbManager.ReadCanonicalHash(111)) 96 97 // 4. After delete, empty hash should be returned. 98 dbManager.DeleteCanonicalHash(111) 99 assert.Equal(t, common.Hash{}, dbManager.ReadCanonicalHash(111)) 100 } 101 102 func testWriteAndReadHeaderHash(t *testing.T, dbManager database.DBManager) { 103 hash1 := common.HexToHash("111") 104 hash2 := common.HexToHash("222") 105 106 // 1. Before write, empty hash should be returned. 107 assert.Equal(t, common.Hash{}, dbManager.ReadHeadHeaderHash()) 108 109 // 2. After write, written hash should be returned. 110 dbManager.WriteHeadHeaderHash(hash1) 111 assert.Equal(t, hash1, dbManager.ReadHeadHeaderHash()) 112 113 // 3. After overwrite, overwritten hash should be returned. 114 dbManager.WriteHeadHeaderHash(hash2) 115 assert.Equal(t, hash2, dbManager.ReadHeadHeaderHash()) 116 117 // 4. Delete operation is not supported. 118 } 119 120 func testWriteAndReadBlockHash(t *testing.T, dbManager database.DBManager) { 121 hash1 := common.HexToHash("111") 122 hash2 := common.HexToHash("222") 123 124 // 1. Before write, empty hash should be returned. 125 assert.Equal(t, common.Hash{}, dbManager.ReadHeadBlockHash()) 126 127 // 2. After write, written hash should be returned. 128 dbManager.WriteHeadBlockHash(hash1) 129 assert.Equal(t, hash1, dbManager.ReadHeadBlockHash()) 130 131 // 3. After overwrite, overwritten hash should be returned. 132 dbManager.WriteHeadBlockHash(hash2) 133 assert.Equal(t, hash2, dbManager.ReadHeadBlockHash()) 134 135 // 4. Delete operation is not supported. 136 } 137 138 func testWriteAndReadFastBlockHash(t *testing.T, dbManager database.DBManager) { 139 hash1 := common.HexToHash("111") 140 hash2 := common.HexToHash("222") 141 142 // 1. Before write, empty hash should be returned. 143 assert.Equal(t, common.Hash{}, dbManager.ReadHeadFastBlockHash()) 144 145 // 2. After write, written hash should be returned. 146 dbManager.WriteHeadFastBlockHash(hash1) 147 assert.Equal(t, hash1, dbManager.ReadHeadFastBlockHash()) 148 149 // 3. After overwrite, overwritten hash should be returned. 150 dbManager.WriteHeadFastBlockHash(hash2) 151 assert.Equal(t, hash2, dbManager.ReadHeadFastBlockHash()) 152 153 // 4. Delete operation is not supported. 154 } 155 156 func testWriteAndReadFastTrieProgress(t *testing.T, dbManager database.DBManager) { 157 // 1. Before write, empty hash should be returned. 158 assert.Equal(t, uint64(0), dbManager.ReadFastTrieProgress()) 159 160 // 2. After write, written hash should be returned. 161 dbManager.WriteFastTrieProgress(111) 162 assert.Equal(t, uint64(111), dbManager.ReadFastTrieProgress()) 163 164 // 3. After overwrite, overwritten hash should be returned. 165 dbManager.WriteFastTrieProgress(222) 166 assert.Equal(t, uint64(222), dbManager.ReadFastTrieProgress()) 167 168 // 4. Delete operation is not supported. 169 } 170 171 func testWriteAndReadHeader(t *testing.T, dbManager database.DBManager) { 172 hash, blockNum, header := generateHeaderWithBlockNum(111) 173 174 // 1. Before write, nil header should be returned. 175 assert.Equal(t, (*types.Header)(nil), dbManager.ReadHeader(hash, blockNum)) 176 177 // 2. After write, written header should be returned. 178 dbManager.WriteHeader(header) 179 assert.Equal(t, header, dbManager.ReadHeader(hash, blockNum)) 180 181 // 3. Overwriting header with identical hash and blockNumber is not possible. 182 183 // 4. After delete, deleted header should not be returned. 184 dbManager.DeleteHeader(hash, blockNum) 185 assert.Equal(t, (*types.Header)(nil), dbManager.ReadHeader(hash, blockNum)) 186 } 187 188 func testWriteAndReadBody(t *testing.T, dbManager database.DBManager) { 189 body := &types.Body{} 190 191 tx := generateTx(t) 192 txs := types.Transactions{tx} 193 body.Transactions = txs 194 195 hash, blockNum, _ := generateHeaderWithBlockNum(111) 196 197 // 1. Before write, nil should be returned. 198 assert.Equal(t, (*types.Body)(nil), dbManager.ReadBody(hash, blockNum)) 199 200 // 2. After write, written body should be returned. 201 dbManager.WriteBody(hash, blockNum, body) 202 assert.Equal(t, body.Transactions[0].Hash(), dbManager.ReadBody(hash, blockNum).Transactions[0].Hash()) 203 204 // 3. Overwriting body with identical hash and blockNumber is not possible. 205 206 // 4. After delete, nil should be returned. 207 dbManager.DeleteBody(hash, blockNum) 208 assert.Equal(t, (*types.Body)(nil), dbManager.ReadBody(hash, blockNum)) 209 } 210 211 func testWriteAndReadTd(t *testing.T, dbManager database.DBManager) { 212 hash1 := common.HexToHash("111") 213 blockNumber1 := uint64(111) 214 215 td1 := new(big.Int).SetUint64(111) 216 td2 := new(big.Int).SetUint64(222) 217 218 // 1. Before write, empty td should be returned. 219 assert.Equal(t, (*big.Int)(nil), dbManager.ReadTd(hash1, blockNumber1)) 220 221 // 2. After write, written td should be returned. 222 dbManager.WriteTd(hash1, blockNumber1, td1) 223 assert.Equal(t, td1, dbManager.ReadTd(hash1, blockNumber1)) 224 225 // 3. After overwrite, overwritten td should be returned. 226 dbManager.WriteTd(hash1, blockNumber1, td2) 227 assert.Equal(t, td2, dbManager.ReadTd(hash1, blockNumber1)) 228 229 // 4. After delete, deleted td should not be returned. 230 dbManager.DeleteTd(hash1, blockNumber1) 231 assert.Equal(t, (*big.Int)(nil), dbManager.ReadTd(hash1, blockNumber1)) 232 } 233 234 func testWriteAndReadReceipts(t *testing.T, dbManager database.DBManager) { 235 receipts := types.Receipts{ 236 generateReceipt(111), 237 generateReceipt(222), 238 generateReceipt(333), 239 } 240 241 hash := common.HexToHash("111") 242 blockNumber := uint64(111) 243 244 // 1. Before write, nil should be returned. 245 assert.Equal(t, (types.Receipts)(nil), dbManager.ReadReceipts(hash, blockNumber)) 246 247 // 2. After write, written receipts should be returned. 248 dbManager.WriteReceipts(hash, blockNumber, receipts) 249 receiptsFromDB := dbManager.ReadReceipts(hash, blockNumber) 250 assert.Equal(t, len(receipts), len(receiptsFromDB)) 251 assert.Equal(t, receipts, receiptsFromDB) 252 253 // 3. After overwrite, overwritten receipts should be returned. 254 receipts2 := types.Receipts{ 255 generateReceipt(444), 256 generateReceipt(555), 257 generateReceipt(666), 258 } 259 dbManager.WriteReceipts(hash, blockNumber, receipts2) 260 receiptsFromDB = dbManager.ReadReceipts(hash, blockNumber) 261 assert.Equal(t, receipts2, receiptsFromDB) 262 assert.NotEqual(t, receipts, receiptsFromDB) 263 264 // 4. After delete, nil should be returned. 265 dbManager.DeleteReceipts(hash, blockNumber) 266 assert.Equal(t, (types.Receipts)(nil), dbManager.ReadReceipts(hash, blockNumber)) 267 } 268 269 func testWriteAndReadBlock(t *testing.T, dbManager database.DBManager) { 270 hash, blockNum, header := generateHeaderWithBlockNum(111) 271 body := generateBody(t) 272 receipts := types.Receipts{generateReceipt(111)} 273 274 blockchain.InitDeriveSha(¶ms.ChainConfig{ 275 DeriveShaImpl: types.ImplDeriveShaOriginal, 276 }) 277 block := types.NewBlock(header, body.Transactions, receipts) 278 279 // 1. Before write, nil should be returned. 280 assert.Equal(t, (*types.Block)(nil), dbManager.ReadBlock(hash, blockNum)) 281 282 // 2. After write, written block should be returned. 283 dbManager.WriteBlock(block) 284 blockFromDB := dbManager.ReadBlock(block.Hash(), block.NumberU64()) 285 assert.Equal(t, block.Header(), blockFromDB.Header()) 286 assert.Equal(t, block.Transactions()[0].Hash(), blockFromDB.Transactions()[0].Hash()) 287 288 // 3. Overwriting block with exact hash and blockNumber is not possible. 289 290 // 4. After delete, nil should be returned. 291 dbManager.DeleteBlock(block.Hash(), block.NumberU64()) 292 assert.Equal(t, (*types.Block)(nil), dbManager.ReadBlock(hash, blockNum)) 293 } 294 295 func testWriteAndReadIstanbulSnapshot(t *testing.T, dbManager database.DBManager) { 296 // TODO-Klaytn-Storage To implement this test case, error shouldn't be returned. 297 } 298 299 func generateHeaderWithBlockNum(blockNum int) (common.Hash, uint64, *types.Header) { 300 parentHash := common.HexToHash(strconv.Itoa(blockNum)) 301 blockNumber := new(big.Int).SetUint64(uint64(blockNum)) 302 303 header := &types.Header{ 304 ParentHash: parentHash, 305 Number: blockNumber, 306 BlockScore: blockNumber, 307 Time: blockNumber, 308 Extra: []byte{'a', 'b', 'c'}, 309 Governance: common.Hex2Bytes("b8dc7b22676f7665726e696e676e6f6465223a22307865373333636234643237396461363936663330643437306638633034646563623534666362306432222c22676f7665726e616e63656d6f6465223a2273696e676c65222c22726577617264223a7b226d696e74696e67616d6f756e74223a393630303030303030303030303030303030302c22726174696f223a2233342f33332f3333227d2c22626674223a7b2265706f6368223a33303030302c22706f6c696379223a302c22737562223a32317d2c22756e69745072696365223a32353030303030303030307d"), 310 Vote: common.Hex2Bytes("e194e733cb4d279da696f30d470f8c04decb54fcb0d28565706f6368853330303030"), 311 } 312 return header.Hash(), uint64(blockNum), header 313 } 314 315 func generateBody(t *testing.T) *types.Body { 316 body := &types.Body{} 317 318 tx := generateTx(t) 319 txs := types.Transactions{tx} 320 body.Transactions = txs 321 322 return body 323 } 324 325 func generateTx(t *testing.T) *types.Transaction { 326 key, _ := crypto.GenerateKey() 327 addr := crypto.PubkeyToAddress(key.PublicKey) 328 329 signer := types.LatestSignerForChainID(big.NewInt(18)) 330 tx1, err := types.SignTx(types.NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil), signer, key) 331 if err != nil { 332 t.Fatal(err) 333 } 334 return tx1 335 } 336 337 func generateReceipt(gasUsed int) *types.Receipt { 338 log := &types.Log{Topics: []common.Hash{}, Data: []uint8{}, BlockNumber: uint64(gasUsed)} 339 log.Topics = append(log.Topics, common.HexToHash(strconv.Itoa(gasUsed))) 340 return &types.Receipt{ 341 TxHash: common.HexToHash(strconv.Itoa(gasUsed)), 342 GasUsed: uint64(gasUsed), 343 Status: types.ReceiptStatusSuccessful, 344 Logs: []*types.Log{log}, 345 } 346 }