github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blkstorage/blockfile_mgr_test.go (about) 1 /* 2 Copyright hechain. 2022 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package blkstorage 8 9 import ( 10 "fmt" 11 "io/ioutil" 12 "os" 13 "testing" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hechain20/hechain/common/ledger/testutil" 17 "github.com/hechain20/hechain/internal/pkg/txflags" 18 "github.com/hechain20/hechain/protoutil" 19 "github.com/hyperledger/fabric-protos-go/common" 20 "github.com/hyperledger/fabric-protos-go/peer" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestBlockfileMgrBlockReadWrite(t *testing.T) { 25 env := newTestEnv(t, NewConf(testPath(), 0)) 26 defer env.Cleanup() 27 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 28 defer blkfileMgrWrapper.close() 29 blocks := testutil.ConstructTestBlocks(t, 10) 30 blkfileMgrWrapper.addBlocks(blocks) 31 blkfileMgrWrapper.testGetBlockByHash(blocks) 32 blkfileMgrWrapper.testGetBlockByNumber(blocks) 33 } 34 35 func TestAddBlockWithWrongHash(t *testing.T) { 36 env := newTestEnv(t, NewConf(testPath(), 0)) 37 defer env.Cleanup() 38 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 39 defer blkfileMgrWrapper.close() 40 blocks := testutil.ConstructTestBlocks(t, 10) 41 blkfileMgrWrapper.addBlocks(blocks[0:9]) 42 lastBlock := blocks[9] 43 lastBlock.Header.PreviousHash = []byte("someJunkHash") // set the hash to something unexpected 44 err := blkfileMgrWrapper.blockfileMgr.addBlock(lastBlock) 45 require.Error(t, err, "An error is expected when adding a block with some unexpected hash") 46 require.Contains(t, err.Error(), "unexpected Previous block hash. Expected PreviousHash") 47 t.Logf("err = %s", err) 48 } 49 50 func TestBlockfileMgrCrashDuringWriting(t *testing.T) { 51 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 10, false) 52 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 1, false) 53 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 0, false) 54 testBlockfileMgrCrashDuringWriting(t, 0, 0, 1000, 10, false) 55 testBlockfileMgrCrashDuringWriting(t, 0, 5, 1000, 10, false) 56 57 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 10, true) 58 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 1, true) 59 testBlockfileMgrCrashDuringWriting(t, 10, 2, 1000, 0, true) 60 testBlockfileMgrCrashDuringWriting(t, 0, 0, 1000, 10, true) 61 testBlockfileMgrCrashDuringWriting(t, 0, 5, 1000, 10, true) 62 } 63 64 func testBlockfileMgrCrashDuringWriting(t *testing.T, numBlksBeforeSavingBlkfilesInfo int, 65 numBlksAfterSavingBlkfilesInfo int, numLastBlockBytes int, numPartialBytesToWrite int, 66 deleteBFInfo bool) { 67 env := newTestEnv(t, NewConf(testPath(), 0)) 68 defer env.Cleanup() 69 ledgerid := "testLedger" 70 blkfileMgrWrapper := newTestBlockfileWrapper(env, ledgerid) 71 bg, gb := testutil.NewBlockGenerator(t, ledgerid, false) 72 73 // create all necessary blocks 74 totalBlocks := numBlksBeforeSavingBlkfilesInfo + numBlksAfterSavingBlkfilesInfo 75 allBlocks := []*common.Block{gb} 76 allBlocks = append(allBlocks, bg.NextTestBlocks(totalBlocks+1)...) 77 78 // identify the blocks that are to be added beforeCP, afterCP, and after restart 79 blocksBeforeSavingBlkfilesInfo := []*common.Block{} 80 blocksAfterSavingBlkfilesInfo := []*common.Block{} 81 if numBlksBeforeSavingBlkfilesInfo != 0 { 82 blocksBeforeSavingBlkfilesInfo = allBlocks[0:numBlksBeforeSavingBlkfilesInfo] 83 } 84 if numBlksAfterSavingBlkfilesInfo != 0 { 85 blocksAfterSavingBlkfilesInfo = allBlocks[numBlksBeforeSavingBlkfilesInfo : numBlksBeforeSavingBlkfilesInfo+numBlksAfterSavingBlkfilesInfo] 86 } 87 blocksAfterRestart := allBlocks[numBlksBeforeSavingBlkfilesInfo+numBlksAfterSavingBlkfilesInfo:] 88 89 // add blocks before cp 90 blkfileMgrWrapper.addBlocks(blocksBeforeSavingBlkfilesInfo) 91 currentBlkfilesInfo := blkfileMgrWrapper.blockfileMgr.blockfilesInfo 92 blkfilesInfo1 := &blockfilesInfo{ 93 latestFileNumber: currentBlkfilesInfo.latestFileNumber, 94 latestFileSize: currentBlkfilesInfo.latestFileSize, 95 noBlockFiles: currentBlkfilesInfo.noBlockFiles, 96 lastPersistedBlock: currentBlkfilesInfo.lastPersistedBlock, 97 } 98 99 // add blocks after cp 100 blkfileMgrWrapper.addBlocks(blocksAfterSavingBlkfilesInfo) 101 blkfilesInfo2 := blkfileMgrWrapper.blockfileMgr.blockfilesInfo 102 103 // simulate a crash scenario 104 lastBlockBytes := []byte{} 105 encodedLen := proto.EncodeVarint(uint64(numLastBlockBytes)) 106 randomBytes := testutil.ConstructRandomBytes(t, numLastBlockBytes) 107 lastBlockBytes = append(lastBlockBytes, encodedLen...) 108 lastBlockBytes = append(lastBlockBytes, randomBytes...) 109 partialBytes := lastBlockBytes[:numPartialBytesToWrite] 110 blkfileMgrWrapper.blockfileMgr.currentFileWriter.append(partialBytes, true) 111 if deleteBFInfo { 112 err := blkfileMgrWrapper.blockfileMgr.db.Delete(blkMgrInfoKey, true) 113 require.NoError(t, err) 114 } else { 115 blkfileMgrWrapper.blockfileMgr.saveBlkfilesInfo(blkfilesInfo1, true) 116 } 117 blkfileMgrWrapper.close() 118 119 // simulate a start after a crash 120 blkfileMgrWrapper = newTestBlockfileWrapper(env, ledgerid) 121 defer blkfileMgrWrapper.close() 122 blkfilesInfo3 := blkfileMgrWrapper.blockfileMgr.blockfilesInfo 123 require.Equal(t, blkfilesInfo2, blkfilesInfo3) 124 125 // add fresh blocks after restart 126 blkfileMgrWrapper.addBlocks(blocksAfterRestart) 127 testBlockfileMgrBlockIterator(t, blkfileMgrWrapper.blockfileMgr, 0, len(allBlocks)-1, allBlocks) 128 } 129 130 func TestBlockfileMgrBlockIterator(t *testing.T) { 131 env := newTestEnv(t, NewConf(testPath(), 0)) 132 defer env.Cleanup() 133 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 134 defer blkfileMgrWrapper.close() 135 blocks := testutil.ConstructTestBlocks(t, 10) 136 blkfileMgrWrapper.addBlocks(blocks) 137 testBlockfileMgrBlockIterator(t, blkfileMgrWrapper.blockfileMgr, 0, 7, blocks[0:8]) 138 } 139 140 func testBlockfileMgrBlockIterator(t *testing.T, blockfileMgr *blockfileMgr, 141 firstBlockNum int, lastBlockNum int, expectedBlocks []*common.Block) { 142 itr, err := blockfileMgr.retrieveBlocks(uint64(firstBlockNum)) 143 require.NoError(t, err, "Error while getting blocks iterator") 144 defer itr.Close() 145 numBlocksItrated := 0 146 for { 147 block, err := itr.Next() 148 require.NoError(t, err, "Error while getting block number [%d] from iterator", numBlocksItrated) 149 require.Equal(t, expectedBlocks[numBlocksItrated], block) 150 numBlocksItrated++ 151 if numBlocksItrated == lastBlockNum-firstBlockNum+1 { 152 break 153 } 154 } 155 require.Equal(t, lastBlockNum-firstBlockNum+1, numBlocksItrated) 156 } 157 158 func TestBlockfileMgrBlockchainInfo(t *testing.T) { 159 env := newTestEnv(t, NewConf(testPath(), 0)) 160 defer env.Cleanup() 161 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 162 defer blkfileMgrWrapper.close() 163 164 bcInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 165 require.Equal(t, &common.BlockchainInfo{Height: 0, CurrentBlockHash: nil, PreviousBlockHash: nil}, bcInfo) 166 167 blocks := testutil.ConstructTestBlocks(t, 10) 168 blkfileMgrWrapper.addBlocks(blocks) 169 bcInfo = blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 170 require.Equal(t, uint64(10), bcInfo.Height) 171 } 172 173 func TestTxIDExists(t *testing.T) { 174 t.Run("green-path", func(t *testing.T) { 175 env := newTestEnv(t, NewConf(testPath(), 0)) 176 defer env.Cleanup() 177 178 blkStore, err := env.provider.Open("testLedger") 179 require.NoError(t, err) 180 defer blkStore.Shutdown() 181 182 blocks := testutil.ConstructTestBlocks(t, 2) 183 for _, blk := range blocks { 184 require.NoError(t, blkStore.AddBlock(blk)) 185 } 186 187 for _, blk := range blocks { 188 for i := range blk.Data.Data { 189 txID, err := protoutil.GetOrComputeTxIDFromEnvelope(blk.Data.Data[i]) 190 require.NoError(t, err) 191 exists, err := blkStore.TxIDExists(txID) 192 require.NoError(t, err) 193 require.True(t, exists) 194 } 195 } 196 exists, err := blkStore.TxIDExists("non-existent-txid") 197 require.NoError(t, err) 198 require.False(t, exists) 199 }) 200 201 t.Run("error-path", func(t *testing.T) { 202 env := newTestEnv(t, NewConf(testPath(), 0)) 203 defer env.Cleanup() 204 205 blkStore, err := env.provider.Open("testLedger") 206 require.NoError(t, err) 207 defer blkStore.Shutdown() 208 209 env.provider.Close() 210 exists, err := blkStore.TxIDExists("random") 211 require.EqualError(t, err, "error while trying to check the presence of TXID [random]: internal leveldb error while obtaining db iterator: leveldb: closed") 212 require.False(t, exists) 213 }) 214 } 215 216 func TestBlockfileMgrGetTxById(t *testing.T) { 217 env := newTestEnv(t, NewConf(testPath(), 0)) 218 defer env.Cleanup() 219 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 220 defer blkfileMgrWrapper.close() 221 blocks := testutil.ConstructTestBlocks(t, 2) 222 blkfileMgrWrapper.addBlocks(blocks) 223 for _, blk := range blocks { 224 for j, txEnvelopeBytes := range blk.Data.Data { 225 // blockNum starts with 0 226 txID, err := protoutil.GetOrComputeTxIDFromEnvelope(blk.Data.Data[j]) 227 require.NoError(t, err) 228 txEnvelopeFromFileMgr, err := blkfileMgrWrapper.blockfileMgr.retrieveTransactionByID(txID) 229 require.NoError(t, err, "Error while retrieving tx from blkfileMgr") 230 txEnvelope, err := protoutil.GetEnvelopeFromBlock(txEnvelopeBytes) 231 require.NoError(t, err, "Error while unmarshalling tx") 232 require.Equal(t, txEnvelope, txEnvelopeFromFileMgr) 233 } 234 } 235 } 236 237 // TestBlockfileMgrGetTxByIdDuplicateTxid tests that a transaction with an existing txid 238 // (within same block or a different block) should not over-write the index by-txid (FAB-8557) 239 func TestBlockfileMgrGetTxByIdDuplicateTxid(t *testing.T) { 240 env := newTestEnv(t, NewConf(testPath(), 0)) 241 defer env.Cleanup() 242 blkStore, err := env.provider.Open("testLedger") 243 require.NoError(env.t, err) 244 blkFileMgr := blkStore.fileMgr 245 bg, gb := testutil.NewBlockGenerator(t, "testLedger", false) 246 require.NoError(t, blkFileMgr.addBlock(gb)) 247 248 block1 := bg.NextBlockWithTxid( 249 [][]byte{ 250 []byte("tx with id=txid-1"), 251 []byte("tx with id=txid-2"), 252 []byte("another tx with existing id=txid-1"), 253 }, 254 []string{"txid-1", "txid-2", "txid-1"}, 255 ) 256 txValidationFlags := txflags.New(3) 257 txValidationFlags.SetFlag(0, peer.TxValidationCode_VALID) 258 txValidationFlags.SetFlag(1, peer.TxValidationCode_INVALID_OTHER_REASON) 259 txValidationFlags.SetFlag(2, peer.TxValidationCode_DUPLICATE_TXID) 260 block1.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txValidationFlags 261 require.NoError(t, blkFileMgr.addBlock(block1)) 262 263 block2 := bg.NextBlockWithTxid( 264 [][]byte{ 265 []byte("tx with id=txid-3"), 266 []byte("yet another tx with existing id=txid-1"), 267 }, 268 []string{"txid-3", "txid-1"}, 269 ) 270 txValidationFlags = txflags.New(2) 271 txValidationFlags.SetFlag(0, peer.TxValidationCode_VALID) 272 txValidationFlags.SetFlag(1, peer.TxValidationCode_DUPLICATE_TXID) 273 block2.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txValidationFlags 274 require.NoError(t, blkFileMgr.addBlock(block2)) 275 276 txenvp1, err := protoutil.GetEnvelopeFromBlock(block1.Data.Data[0]) 277 require.NoError(t, err) 278 txenvp2, err := protoutil.GetEnvelopeFromBlock(block1.Data.Data[1]) 279 require.NoError(t, err) 280 txenvp3, err := protoutil.GetEnvelopeFromBlock(block2.Data.Data[0]) 281 require.NoError(t, err) 282 283 indexedTxenvp, _ := blkFileMgr.retrieveTransactionByID("txid-1") 284 require.Equal(t, txenvp1, indexedTxenvp) 285 indexedTxenvp, _ = blkFileMgr.retrieveTransactionByID("txid-2") 286 require.Equal(t, txenvp2, indexedTxenvp) 287 indexedTxenvp, _ = blkFileMgr.retrieveTransactionByID("txid-3") 288 require.Equal(t, txenvp3, indexedTxenvp) 289 290 blk, _ := blkFileMgr.retrieveBlockByTxID("txid-1") 291 require.Equal(t, block1, blk) 292 blk, _ = blkFileMgr.retrieveBlockByTxID("txid-2") 293 require.Equal(t, block1, blk) 294 blk, _ = blkFileMgr.retrieveBlockByTxID("txid-3") 295 require.Equal(t, block2, blk) 296 297 validationCode, blkNum, _ := blkFileMgr.retrieveTxValidationCodeByTxID("txid-1") 298 require.Equal(t, peer.TxValidationCode_VALID, validationCode) 299 require.Equal(t, uint64(1), blkNum) 300 validationCode, blkNum, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-2") 301 require.Equal(t, peer.TxValidationCode_INVALID_OTHER_REASON, validationCode) 302 require.Equal(t, uint64(1), blkNum) 303 validationCode, blkNum, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-3") 304 require.Equal(t, peer.TxValidationCode_VALID, validationCode) 305 require.Equal(t, uint64(2), blkNum) 306 307 // though we do not expose an API for retrieving all the txs by same id but we may in future 308 // and the data is persisted to support this. below code tests this behavior internally 309 w := &testBlockfileMgrWrapper{ 310 t: t, 311 blockfileMgr: blkFileMgr, 312 } 313 w.testGetMultipleDataByTxID( 314 "txid-1", 315 []*expectedBlkTxValidationCode{ 316 { 317 blk: block1, 318 txEnv: protoutil.ExtractEnvelopeOrPanic(block1, 0), 319 validationCode: peer.TxValidationCode_VALID, 320 }, 321 { 322 blk: block1, 323 txEnv: protoutil.ExtractEnvelopeOrPanic(block1, 2), 324 validationCode: peer.TxValidationCode_DUPLICATE_TXID, 325 }, 326 { 327 blk: block2, 328 txEnv: protoutil.ExtractEnvelopeOrPanic(block2, 1), 329 validationCode: peer.TxValidationCode_DUPLICATE_TXID, 330 }, 331 }, 332 ) 333 334 w.testGetMultipleDataByTxID( 335 "txid-2", 336 []*expectedBlkTxValidationCode{ 337 { 338 blk: block1, 339 txEnv: protoutil.ExtractEnvelopeOrPanic(block1, 1), 340 validationCode: peer.TxValidationCode_INVALID_OTHER_REASON, 341 }, 342 }, 343 ) 344 345 w.testGetMultipleDataByTxID( 346 "txid-3", 347 []*expectedBlkTxValidationCode{ 348 { 349 blk: block2, 350 txEnv: protoutil.ExtractEnvelopeOrPanic(block2, 0), 351 validationCode: peer.TxValidationCode_VALID, 352 }, 353 }, 354 ) 355 } 356 357 func TestBlockfileMgrGetTxByBlockNumTranNum(t *testing.T) { 358 env := newTestEnv(t, NewConf(testPath(), 0)) 359 defer env.Cleanup() 360 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 361 defer blkfileMgrWrapper.close() 362 blocks := testutil.ConstructTestBlocks(t, 10) 363 blkfileMgrWrapper.addBlocks(blocks) 364 for blockIndex, blk := range blocks { 365 for tranIndex, txEnvelopeBytes := range blk.Data.Data { 366 // blockNum and tranNum both start with 0 367 txEnvelopeFromFileMgr, err := blkfileMgrWrapper.blockfileMgr.retrieveTransactionByBlockNumTranNum(uint64(blockIndex), uint64(tranIndex)) 368 require.NoError(t, err, "Error while retrieving tx from blkfileMgr") 369 txEnvelope, err := protoutil.GetEnvelopeFromBlock(txEnvelopeBytes) 370 require.NoError(t, err, "Error while unmarshalling tx") 371 require.Equal(t, txEnvelope, txEnvelopeFromFileMgr) 372 } 373 } 374 } 375 376 func TestBlockfileMgrRestart(t *testing.T) { 377 env := newTestEnv(t, NewConf(testPath(), 0)) 378 defer env.Cleanup() 379 ledgerid := "testLedger" 380 blkfileMgrWrapper := newTestBlockfileWrapper(env, ledgerid) 381 blocks := testutil.ConstructTestBlocks(t, 10) 382 blkfileMgrWrapper.addBlocks(blocks) 383 expectedHeight := uint64(10) 384 require.Equal(t, expectedHeight, blkfileMgrWrapper.blockfileMgr.getBlockchainInfo().Height) 385 blkfileMgrWrapper.close() 386 387 blkfileMgrWrapper = newTestBlockfileWrapper(env, ledgerid) 388 defer blkfileMgrWrapper.close() 389 require.Equal(t, 9, int(blkfileMgrWrapper.blockfileMgr.blockfilesInfo.lastPersistedBlock)) 390 blkfileMgrWrapper.testGetBlockByHash(blocks) 391 require.Equal(t, expectedHeight, blkfileMgrWrapper.blockfileMgr.getBlockchainInfo().Height) 392 } 393 394 func TestBlockfileMgrFileRolling(t *testing.T) { 395 blocks := testutil.ConstructTestBlocks(t, 200) 396 size := 0 397 for _, block := range blocks[:100] { 398 by, _, err := serializeBlock(block) 399 require.NoError(t, err, "Error while serializing block") 400 blockBytesSize := len(by) 401 encodedLen := proto.EncodeVarint(uint64(blockBytesSize)) 402 size += blockBytesSize + len(encodedLen) 403 } 404 405 maxFileSie := int(0.75 * float64(size)) 406 env := newTestEnv(t, NewConf(testPath(), maxFileSie)) 407 defer env.Cleanup() 408 ledgerid := "testLedger" 409 blkfileMgrWrapper := newTestBlockfileWrapper(env, ledgerid) 410 blkfileMgrWrapper.addBlocks(blocks[:100]) 411 require.Equal(t, 1, blkfileMgrWrapper.blockfileMgr.blockfilesInfo.latestFileNumber) 412 blkfileMgrWrapper.testGetBlockByHash(blocks[:100]) 413 blkfileMgrWrapper.close() 414 415 blkfileMgrWrapper = newTestBlockfileWrapper(env, ledgerid) 416 defer blkfileMgrWrapper.close() 417 blkfileMgrWrapper.addBlocks(blocks[100:]) 418 require.Equal(t, 2, blkfileMgrWrapper.blockfileMgr.blockfilesInfo.latestFileNumber) 419 blkfileMgrWrapper.testGetBlockByHash(blocks[100:]) 420 } 421 422 func TestBlockfileMgrGetBlockByTxID(t *testing.T) { 423 env := newTestEnv(t, NewConf(testPath(), 0)) 424 defer env.Cleanup() 425 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 426 defer blkfileMgrWrapper.close() 427 blocks := testutil.ConstructTestBlocks(t, 10) 428 blkfileMgrWrapper.addBlocks(blocks) 429 for _, blk := range blocks { 430 for j := range blk.Data.Data { 431 // blockNum starts with 1 432 txID, err := protoutil.GetOrComputeTxIDFromEnvelope(blk.Data.Data[j]) 433 require.NoError(t, err) 434 435 blockFromFileMgr, err := blkfileMgrWrapper.blockfileMgr.retrieveBlockByTxID(txID) 436 require.NoError(t, err, "Error while retrieving block from blkfileMgr") 437 require.Equal(t, blk, blockFromFileMgr) 438 } 439 } 440 } 441 442 func TestBlockfileMgrSimulateCrashAtFirstBlockInFile(t *testing.T) { 443 t.Run("blockfilesInfo persisted", func(t *testing.T) { 444 testBlockfileMgrSimulateCrashAtFirstBlockInFile(t, false) 445 }) 446 447 t.Run("blockfilesInfo to be computed from block files", func(t *testing.T) { 448 testBlockfileMgrSimulateCrashAtFirstBlockInFile(t, true) 449 }) 450 } 451 452 func testBlockfileMgrSimulateCrashAtFirstBlockInFile(t *testing.T, deleteBlkfilesInfo bool) { 453 // open blockfileMgr and add 5 blocks 454 env := newTestEnv(t, NewConf(testPath(), 0)) 455 defer env.Cleanup() 456 457 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 458 blockfileMgr := blkfileMgrWrapper.blockfileMgr 459 blocks := testutil.ConstructTestBlocks(t, 10) 460 for i := 0; i < 10; i++ { 461 fmt.Printf("blocks[i].Header.Number = %d\n", blocks[i].Header.Number) 462 } 463 blkfileMgrWrapper.addBlocks(blocks[:5]) 464 firstFilePath := blockfileMgr.currentFileWriter.filePath 465 firstBlkFileSize := testutilGetFileSize(t, firstFilePath) 466 467 // move to next file and simulate crash scenario while writing the first block 468 blockfileMgr.moveToNextFile() 469 partialBytesForNextBlock := append( 470 proto.EncodeVarint(uint64(10000)), 471 []byte("partialBytesForNextBlock depicting a crash during first block in file")..., 472 ) 473 blockfileMgr.currentFileWriter.append(partialBytesForNextBlock, true) 474 if deleteBlkfilesInfo { 475 err := blockfileMgr.db.Delete(blkMgrInfoKey, true) 476 require.NoError(t, err) 477 } 478 blkfileMgrWrapper.close() 479 480 // verify that the block file number 1 has been created with partial bytes as a side-effect of crash 481 lastFilePath := blockfileMgr.currentFileWriter.filePath 482 lastFileContent, err := ioutil.ReadFile(lastFilePath) 483 require.NoError(t, err) 484 require.Equal(t, lastFileContent, partialBytesForNextBlock) 485 486 // simulate reopen after crash 487 blkfileMgrWrapper = newTestBlockfileWrapper(env, "testLedger") 488 defer blkfileMgrWrapper.close() 489 490 // last block file (block file number 1) should have been truncated to zero length and concluded as the next file to append to 491 require.Equal(t, 0, testutilGetFileSize(t, lastFilePath)) 492 require.Equal(t, 493 &blockfilesInfo{ 494 latestFileNumber: 1, 495 latestFileSize: 0, 496 lastPersistedBlock: 4, 497 noBlockFiles: false, 498 }, 499 blkfileMgrWrapper.blockfileMgr.blockfilesInfo, 500 ) 501 502 // Add 5 more blocks and assert that they are added to last file (block file number 1) and full scanning across two files works as expected 503 blkfileMgrWrapper.addBlocks(blocks[5:]) 504 require.True(t, testutilGetFileSize(t, lastFilePath) > 0) 505 require.Equal(t, firstBlkFileSize, testutilGetFileSize(t, firstFilePath)) 506 blkfileMgrWrapper.testGetBlockByNumber(blocks) 507 testBlockfileMgrBlockIterator(t, blkfileMgrWrapper.blockfileMgr, 0, len(blocks)-1, blocks) 508 } 509 510 func testutilGetFileSize(t *testing.T, path string) int { 511 fi, err := os.Stat(path) 512 require.NoError(t, err) 513 return int(fi.Size()) 514 }