| 1095 | } |
| 1096 | |
| 1097 | BlockManager::ReadRawBlockResult BlockManager::ReadRawBlock(const FlatFilePos& pos, std::optional<std::pair<size_t, size_t>> block_part) const |
| 1098 | { |
| 1099 | if (pos.nPos < STORAGE_HEADER_BYTES) { |
| 1100 | // If nPos is less than STORAGE_HEADER_BYTES, we can't read the header that precedes the block data |
| 1101 | // This would cause an unsigned integer underflow when trying to position the file cursor |
| 1102 | // This can happen after pruning or default constructed positions |
| 1103 | LogError("Failed for %s while reading raw block storage header", pos.ToString()); |
| 1104 | return util::Unexpected{ReadRawError::IO}; |
| 1105 | } |
| 1106 | AutoFile filein{OpenBlockFile({pos.nFile, pos.nPos - STORAGE_HEADER_BYTES}, /*fReadOnly=*/true)}; |
| 1107 | if (filein.IsNull()) { |
| 1108 | LogError("OpenBlockFile failed for %s while reading raw block", pos.ToString()); |
| 1109 | return util::Unexpected{ReadRawError::IO}; |
| 1110 | } |
| 1111 | |
| 1112 | try { |
| 1113 | MessageStartChars blk_start; |
| 1114 | unsigned int blk_size; |
| 1115 | |
| 1116 | filein >> blk_start >> blk_size; |
| 1117 | |
| 1118 | if (blk_start != GetParams().MessageStart()) { |
| 1119 | LogError("Block magic mismatch for %s: %s versus expected %s while reading raw block", |
| 1120 | pos.ToString(), HexStr(blk_start), HexStr(GetParams().MessageStart())); |
| 1121 | return util::Unexpected{ReadRawError::IO}; |
| 1122 | } |
| 1123 | |
| 1124 | if (blk_size > MAX_SIZE) { |
| 1125 | LogError("Block data is larger than maximum deserialization size for %s: %s versus %s while reading raw block", |
| 1126 | pos.ToString(), blk_size, MAX_SIZE); |
| 1127 | return util::Unexpected{ReadRawError::IO}; |
| 1128 | } |
| 1129 | |
| 1130 | if (block_part) { |
| 1131 | const auto [offset, size]{*block_part}; |
| 1132 | if (size == 0 || SaturatingAdd(offset, size) > blk_size) { |
| 1133 | return util::Unexpected{ReadRawError::BadPartRange}; // Avoid logging - offset/size come from untrusted REST input |
| 1134 | } |
| 1135 | filein.seek(offset, SEEK_CUR); |
| 1136 | blk_size = size; |
| 1137 | } |
| 1138 | |
| 1139 | std::vector<std::byte> data(blk_size); // Zeroing of memory is intentional here |
| 1140 | filein.read(data); |
| 1141 | return data; |
| 1142 | } catch (const std::exception& e) { |
| 1143 | LogError("Read from block file failed: %s for %s while reading raw block", e.what(), pos.ToString()); |
| 1144 | return util::Unexpected{ReadRawError::IO}; |
| 1145 | } |
| 1146 | } |
| 1147 | |
| 1148 | FlatFilePos BlockManager::WriteBlock(const CBlock& block, int nHeight) |
| 1149 | { |