| 979 | } |
| 980 | |
| 981 | bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) |
| 982 | { |
| 983 | AssertLockHeld(::cs_main); |
| 984 | const BlockfileType type = BlockfileTypeForHeight(block.nHeight); |
| 985 | auto& cursor = *Assert(m_blockfile_cursors[type]); |
| 986 | |
| 987 | // Write undo information to disk |
| 988 | if (block.GetUndoPos().IsNull()) { |
| 989 | FlatFilePos pos; |
| 990 | const auto blockundo_size{static_cast<uint32_t>(GetSerializeSize(blockundo))}; |
| 991 | if (!FindUndoPos(state, block.nFile, pos, blockundo_size + UNDO_DATA_DISK_OVERHEAD)) { |
| 992 | LogError("FindUndoPos failed for %s while writing block undo", pos.ToString()); |
| 993 | return false; |
| 994 | } |
| 995 | |
| 996 | // Open history file to append |
| 997 | AutoFile file{OpenUndoFile(pos)}; |
| 998 | if (file.IsNull()) { |
| 999 | LogError("OpenUndoFile failed for %s while writing block undo", pos.ToString()); |
| 1000 | return FatalError(m_opts.notifications, state, _("Failed to write undo data.")); |
| 1001 | } |
| 1002 | { |
| 1003 | BufferedWriter fileout{file}; |
| 1004 | |
| 1005 | // Write index header |
| 1006 | fileout << GetParams().MessageStart() << blockundo_size; |
| 1007 | pos.nPos += STORAGE_HEADER_BYTES; |
| 1008 | { |
| 1009 | // Calculate checksum |
| 1010 | HashWriter hasher{}; |
| 1011 | hasher << block.pprev->GetBlockHash() << blockundo; |
| 1012 | // Write undo data & checksum |
| 1013 | fileout << blockundo << hasher.GetHash(); |
| 1014 | } |
| 1015 | // BufferedWriter will flush pending data to file when fileout goes out of scope. |
| 1016 | } |
| 1017 | |
| 1018 | // Make sure that the file is closed before we call `FlushUndoFile`. |
| 1019 | if (file.fclose() != 0) { |
| 1020 | LogError("Failed to close block undo file %s: %s", pos.ToString(), SysErrorString(errno)); |
| 1021 | return FatalError(m_opts.notifications, state, _("Failed to close block undo file.")); |
| 1022 | } |
| 1023 | |
| 1024 | // rev files are written in block height order, whereas blk files are written as blocks come in (often out of order) |
| 1025 | // we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height |
| 1026 | // in the block file info as below; note that this does not catch the case where the undo writes are keeping up |
| 1027 | // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in |
| 1028 | // the FindNextBlockPos function |
| 1029 | if (pos.nFile < cursor.file_num && static_cast<uint32_t>(block.nHeight) == m_blockfile_info[pos.nFile].nHeightLast) { |
| 1030 | // Do not propagate the return code, a failed flush here should not |
| 1031 | // be an indication for a failed write. If it were propagated here, |
| 1032 | // the caller would assume the undo data not to be written, when in |
| 1033 | // fact it is. Note though, that a failed flush might leave the data |
| 1034 | // file untrimmed. |
| 1035 | if (!FlushUndoFile(pos.nFile, true)) { |
| 1036 | LogWarning("Failed to flush undo file %05i\n", pos.nFile); |
| 1037 | } |
| 1038 | } else if (pos.nFile == cursor.file_num && block.nHeight > cursor.undo_height) { |
no test coverage detected