@@ -529,7 +529,7 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
529
529
}
530
530
for (std::set<int >::iterator it = setBlkDataFiles.begin (); it != setBlkDataFiles.end (); it++) {
531
531
FlatFilePos pos (*it, 0 );
532
- if (OpenBlockFile (pos, true ).IsNull ()) {
532
+ if (OpenBlockFile (pos, /* fReadOnly= */ true ).IsNull ()) {
533
533
return false ;
534
534
}
535
535
}
@@ -660,27 +660,30 @@ bool BlockManager::ReadBlockUndo(CBlockUndo& blockundo, const CBlockIndex& index
660
660
const FlatFilePos pos{WITH_LOCK (::cs_main, return index.GetUndoPos ())};
661
661
662
662
// Open history file to read
663
- AutoFile filein {OpenUndoFile (pos, true )};
664
- if (filein .IsNull ()) {
665
- LogError (" OpenUndoFile failed for %s" , pos.ToString ());
663
+ AutoFile file {OpenUndoFile (pos, true )};
664
+ if (file .IsNull ()) {
665
+ LogError (" OpenUndoFile failed for %s while reading block undo " , pos.ToString ());
666
666
return false ;
667
667
}
668
+ BufferedReader filein{std::move (file)};
668
669
669
- // Read block
670
- uint256 hashChecksum;
671
- HashVerifier verifier{filein}; // Use HashVerifier as reserializing may lose data, c.f. commit d342424301013ec47dc146a4beb49d5c9319d80a
672
670
try {
671
+ // Read block
672
+ HashVerifier verifier{filein}; // Use HashVerifier, as reserializing may lose data, c.f. commit d3424243
673
+
673
674
verifier << index.pprev ->GetBlockHash ();
674
675
verifier >> blockundo;
676
+
677
+ uint256 hashChecksum;
675
678
filein >> hashChecksum;
676
- } catch (const std::exception& e) {
677
- LogError (" %s: Deserialize or I/O error - %s at %s\n " , __func__, e.what (), pos.ToString ());
678
- return false ;
679
- }
680
679
681
- // Verify checksum
682
- if (hashChecksum != verifier.GetHash ()) {
683
- LogError (" %s: Checksum mismatch at %s\n " , __func__, pos.ToString ());
680
+ // Verify checksum
681
+ if (hashChecksum != verifier.GetHash ()) {
682
+ LogError (" Checksum mismatch at %s while reading block undo" , pos.ToString ());
683
+ return false ;
684
+ }
685
+ } catch (const std::exception& e) {
686
+ LogError (" Deserialize or I/O error - %s at %s while reading block undo" , e.what (), pos.ToString ());
684
687
return false ;
685
688
}
686
689
@@ -931,29 +934,34 @@ bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationSt
931
934
// Write undo information to disk
932
935
if (block.GetUndoPos ().IsNull ()) {
933
936
FlatFilePos pos;
934
- const unsigned int blockundo_size{static_cast <unsigned int >(GetSerializeSize (blockundo))};
937
+ const auto blockundo_size{static_cast <uint32_t >(GetSerializeSize (blockundo))};
935
938
if (!FindUndoPos (state, block.nFile , pos, blockundo_size + UNDO_DATA_DISK_OVERHEAD)) {
936
- LogError (" FindUndoPos failed" );
939
+ LogError (" FindUndoPos failed for %s while writing block undo " , pos. ToString () );
937
940
return false ;
938
941
}
939
- // Open history file to append
940
- AutoFile fileout{OpenUndoFile (pos)};
941
- if (fileout.IsNull ()) {
942
- LogError (" OpenUndoFile failed" );
943
- return FatalError (m_opts.notifications , state, _ (" Failed to write undo data." ));
944
- }
945
942
946
- // Write index header
947
- fileout << GetParams ().MessageStart () << blockundo_size;
948
- // Write undo data
949
- pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
950
- fileout << blockundo;
943
+ {
944
+ // Open history file to append
945
+ AutoFile file{OpenUndoFile (pos)};
946
+ if (file.IsNull ()) {
947
+ LogError (" OpenUndoFile failed for %s while writing block undo" , pos.ToString ());
948
+ return FatalError (m_opts.notifications , state, _ (" Failed to write undo data." ));
949
+ }
950
+ BufferedWriter fileout{file};
951
+
952
+ // Write index header
953
+ fileout << GetParams ().MessageStart () << blockundo_size;
954
+ pos.nPos += STORAGE_HEADER_BYTES;
955
+ {
956
+ // Calculate checksum
957
+ HashWriter hasher{};
958
+ hasher << block.pprev ->GetBlockHash () << blockundo;
959
+ // Write undo data & checksum
960
+ fileout << blockundo << hasher.GetHash ();
961
+ }
951
962
952
- // Calculate & write checksum
953
- HashWriter hasher{};
954
- hasher << block.pprev ->GetBlockHash ();
955
- hasher << blockundo;
956
- fileout << hasher.GetHash ();
963
+ fileout.flush (); // Make sure `AutoFile`/`BufferedWriter` go out of scope before we call `FlushUndoFile`
964
+ }
957
965
958
966
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
959
967
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
@@ -986,29 +994,28 @@ bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos) const
986
994
block.SetNull ();
987
995
988
996
// Open history file to read
989
- AutoFile filein{OpenBlockFile (pos, true )};
990
- if (filein.IsNull ()) {
991
- LogError (" %s: OpenBlockFile failed for %s\n " , __func__, pos.ToString ());
997
+ std::vector<uint8_t > block_data;
998
+ if (!ReadRawBlock (block_data, pos)) {
992
999
return false ;
993
1000
}
994
1001
995
- // Read block
996
1002
try {
997
- filein >> TX_WITH_WITNESS (block);
1003
+ // Read block
1004
+ SpanReader{block_data} >> TX_WITH_WITNESS (block);
998
1005
} catch (const std::exception& e) {
999
- LogError (" %s: Deserialize or I/O error - %s at %s\n " , __func__ , e.what (), pos.ToString ());
1006
+ LogError (" Deserialize or I/O error - %s at %s while reading block " , e.what (), pos.ToString ());
1000
1007
return false ;
1001
1008
}
1002
1009
1003
1010
// Check the header
1004
1011
if (!CheckProofOfWork (block.GetHash (), block.nBits , GetConsensus ())) {
1005
- LogError (" %s: Errors in block header at %s\n " , __func__ , pos.ToString ());
1012
+ LogError (" Errors in block header at %s while reading block " , pos.ToString ());
1006
1013
return false ;
1007
1014
}
1008
1015
1009
1016
// Signet only: check block solution
1010
1017
if (GetConsensus ().signet_blocks && !CheckSignetBlockSolution (block, GetConsensus ())) {
1011
- LogError (" %s: Errors in block solution at %s\n " , __func__ , pos.ToString ());
1018
+ LogError (" Errors in block solution at %s while reading block " , pos.ToString ());
1012
1019
return false ;
1013
1020
}
1014
1021
@@ -1023,25 +1030,24 @@ bool BlockManager::ReadBlock(CBlock& block, const CBlockIndex& index) const
1023
1030
return false ;
1024
1031
}
1025
1032
if (block.GetHash () != index.GetBlockHash ()) {
1026
- LogError (" %s: GetHash() doesn't match index for %s at %s\n " , __func__ , index.ToString (), block_pos.ToString ());
1033
+ LogError (" GetHash() doesn't match index for %s at %s while reading block " , index.ToString (), block_pos.ToString ());
1027
1034
return false ;
1028
1035
}
1029
1036
return true ;
1030
1037
}
1031
1038
1032
1039
bool BlockManager::ReadRawBlock (std::vector<uint8_t >& block, const FlatFilePos& pos) const
1033
1040
{
1034
- FlatFilePos hpos = pos;
1035
- // If nPos is less than 8 the pos is null and we don't have the block data
1036
- // Return early to prevent undefined behavior of unsigned int underflow
1037
- if (hpos. nPos < 8 ) {
1038
- LogError (" %s: OpenBlockFile failed for %s \n " , __func__ , pos.ToString ());
1041
+ if (pos. nPos < STORAGE_HEADER_BYTES) {
1042
+ // If nPos is less than STORAGE_HEADER_BYTES, we can't read the header that precedes the block data
1043
+ // This would cause an unsigned integer underflow when trying to position the file cursor
1044
+ // This can happen after pruning or default constructed positions
1045
+ LogError (" Failed for %s while reading raw block storage header " , pos.ToString ());
1039
1046
return false ;
1040
1047
}
1041
- hpos.nPos -= 8 ; // Seek back 8 bytes for meta header
1042
- AutoFile filein{OpenBlockFile (hpos, true )};
1048
+ AutoFile filein{OpenBlockFile ({pos.nFile , pos.nPos - STORAGE_HEADER_BYTES}, /* fReadOnly=*/ true )};
1043
1049
if (filein.IsNull ()) {
1044
- LogError (" %s: OpenBlockFile failed for %s\n " , __func__ , pos.ToString ());
1050
+ LogError (" OpenBlockFile failed for %s while reading raw block " , pos.ToString ());
1045
1051
return false ;
1046
1052
}
1047
1053
@@ -1052,22 +1058,21 @@ bool BlockManager::ReadRawBlock(std::vector<uint8_t>& block, const FlatFilePos&
1052
1058
filein >> blk_start >> blk_size;
1053
1059
1054
1060
if (blk_start != GetParams ().MessageStart ()) {
1055
- LogError (" %s: Block magic mismatch for %s: %s versus expected %s\n " , __func__, pos.ToString (),
1056
- HexStr (blk_start),
1057
- HexStr (GetParams ().MessageStart ()));
1061
+ LogError (" Block magic mismatch for %s: %s versus expected %s while reading raw block" ,
1062
+ pos.ToString (), HexStr (blk_start), HexStr (GetParams ().MessageStart ()));
1058
1063
return false ;
1059
1064
}
1060
1065
1061
1066
if (blk_size > MAX_SIZE) {
1062
- LogError (" %s: Block data is larger than maximum deserialization size for %s: %s versus %s\n " , __func__, pos. ToString () ,
1063
- blk_size, MAX_SIZE);
1067
+ LogError (" Block data is larger than maximum deserialization size for %s: %s versus %s while reading raw block " ,
1068
+ pos. ToString (), blk_size, MAX_SIZE);
1064
1069
return false ;
1065
1070
}
1066
1071
1067
1072
block.resize (blk_size); // Zeroing of memory is intentional here
1068
1073
filein.read (MakeWritableByteSpan (block));
1069
1074
} catch (const std::exception& e) {
1070
- LogError (" %s: Read from block file failed: %s for %s\n " , __func__ , e.what (), pos.ToString ());
1075
+ LogError (" Read from block file failed: %s for %s while reading raw block " , e.what (), pos.ToString ());
1071
1076
return false ;
1072
1077
}
1073
1078
@@ -1077,22 +1082,23 @@ bool BlockManager::ReadRawBlock(std::vector<uint8_t>& block, const FlatFilePos&
1077
1082
FlatFilePos BlockManager::WriteBlock (const CBlock& block, int nHeight)
1078
1083
{
1079
1084
const unsigned int block_size{static_cast <unsigned int >(GetSerializeSize (TX_WITH_WITNESS (block)))};
1080
- FlatFilePos pos{FindNextBlockPos (block_size + BLOCK_SERIALIZATION_HEADER_SIZE , nHeight, block.GetBlockTime ())};
1085
+ FlatFilePos pos{FindNextBlockPos (block_size + STORAGE_HEADER_BYTES , nHeight, block.GetBlockTime ())};
1081
1086
if (pos.IsNull ()) {
1082
- LogError (" FindNextBlockPos failed" );
1087
+ LogError (" FindNextBlockPos failed for %s while writing block " , pos. ToString () );
1083
1088
return FlatFilePos ();
1084
1089
}
1085
- AutoFile fileout {OpenBlockFile (pos)};
1086
- if (fileout .IsNull ()) {
1087
- LogError (" OpenBlockFile failed" );
1090
+ AutoFile file {OpenBlockFile (pos, /* fReadOnly= */ false )};
1091
+ if (file .IsNull ()) {
1092
+ LogError (" OpenBlockFile failed for %s while writing block " , pos. ToString () );
1088
1093
m_opts.notifications .fatalError (_ (" Failed to write block." ));
1089
1094
return FlatFilePos ();
1090
1095
}
1096
+ BufferedWriter fileout{file};
1091
1097
1092
1098
// Write index header
1093
1099
fileout << GetParams ().MessageStart () << block_size;
1100
+ pos.nPos += STORAGE_HEADER_BYTES;
1094
1101
// Write block
1095
- pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
1096
1102
fileout << TX_WITH_WITNESS (block);
1097
1103
return pos;
1098
1104
}
@@ -1201,7 +1207,7 @@ void ImportBlocks(ChainstateManager& chainman, std::span<const fs::path> import_
1201
1207
if (!fs::exists (chainman.m_blockman .GetBlockPosFilename (pos))) {
1202
1208
break ; // No block files left to reindex
1203
1209
}
1204
- AutoFile file{chainman.m_blockman .OpenBlockFile (pos, true )};
1210
+ AutoFile file{chainman.m_blockman .OpenBlockFile (pos, /* fReadOnly= */ true )};
1205
1211
if (file.IsNull ()) {
1206
1212
break ; // This error is logged in OpenBlockFile
1207
1213
}
0 commit comments