Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show All 12 Lines | |||||
#include <checkpoints.h> | #include <checkpoints.h> | ||||
#include <checkqueue.h> | #include <checkqueue.h> | ||||
#include <config.h> | #include <config.h> | ||||
#include <consensus/activation.h> | #include <consensus/activation.h> | ||||
#include <consensus/consensus.h> | #include <consensus/consensus.h> | ||||
#include <consensus/merkle.h> | #include <consensus/merkle.h> | ||||
#include <consensus/tx_verify.h> | #include <consensus/tx_verify.h> | ||||
#include <consensus/validation.h> | #include <consensus/validation.h> | ||||
#include <flatfile.h> | |||||
#include <fs.h> | #include <fs.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <index/txindex.h> | #include <index/txindex.h> | ||||
#include <init.h> | #include <init.h> | ||||
#include <policy/fees.h> | #include <policy/fees.h> | ||||
#include <policy/policy.h> | #include <policy/policy.h> | ||||
#include <pow.h> | #include <pow.h> | ||||
#include <primitives/block.h> | #include <primitives/block.h> | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | |||||
static bool FlushStateToDisk(const CChainParams &chainParams, | static bool FlushStateToDisk(const CChainParams &chainParams, | ||||
CValidationState &state, FlushStateMode mode, | CValidationState &state, FlushStateMode mode, | ||||
int nManualPruneHeight = 0); | int nManualPruneHeight = 0); | ||||
static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | ||||
int nManualPruneHeight); | int nManualPruneHeight); | ||||
static void FindFilesToPrune(std::set<int> &setFilesToPrune, | static void FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
uint64_t nPruneAfterHeight); | uint64_t nPruneAfterHeight); | ||||
static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); | static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); | ||||
static FlatFileSeq BlockFileSeq(); | |||||
static FlatFileSeq UndoFileSeq(); | |||||
static uint32_t GetNextBlockScriptFlags(const Config &config, | static uint32_t GetNextBlockScriptFlags(const Config &config, | ||||
const CBlockIndex *pindex); | const CBlockIndex *pindex); | ||||
bool TestLockPointValidity(const LockPoints *lp) { | bool TestLockPointValidity(const LockPoints *lp) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(lp); | assert(lp); | ||||
// If there are relative lock times then the maxInputBlock will be set | // If there are relative lock times then the maxInputBlock will be set | ||||
// If there are no relative lock times, the LockPoints don't depend on the | // If there are no relative lock times, the LockPoints don't depend on the | ||||
▲ Show 20 Lines • Show All 1,159 Lines • ▼ Show 20 Lines | DisconnectResult ApplyBlockUndo(const CBlockUndo &blockUndo, | ||||
view.SetBestBlock(block.hashPrevBlock); | view.SetBestBlock(block.hashPrevBlock); | ||||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | ||||
} | } | ||||
static void FlushBlockFile(bool fFinalize = false) { | static void FlushBlockFile(bool fFinalize = false) { | ||||
LOCK(cs_LastBlockFile); | LOCK(cs_LastBlockFile); | ||||
CDiskBlockPos posOld(nLastBlockFile, 0); | CDiskBlockPos block_pos_old(nLastBlockFile, | ||||
bool status = true; | vinfoBlockFile[nLastBlockFile].nSize); | ||||
CDiskBlockPos undo_pos_old(nLastBlockFile, | |||||
FILE *fileOld = OpenBlockFile(posOld); | vinfoBlockFile[nLastBlockFile].nUndoSize); | ||||
if (fileOld) { | |||||
if (fFinalize) { | |||||
status &= | |||||
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); | |||||
} | |||||
status &= FileCommit(fileOld); | |||||
fclose(fileOld); | |||||
} | |||||
fileOld = OpenUndoFile(posOld); | |||||
if (fileOld) { | |||||
if (fFinalize) { | |||||
status &= | |||||
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); | |||||
} | |||||
status &= FileCommit(fileOld); | |||||
fclose(fileOld); | |||||
} | |||||
bool status = true; | |||||
status &= BlockFileSeq().Flush(block_pos_old, fFinalize); | |||||
status &= UndoFileSeq().Flush(undo_pos_old, fFinalize); | |||||
if (!status) { | if (!status) { | ||||
AbortNode("Flushing block file to disk failed. This is likely the " | AbortNode("Flushing block file to disk failed. This is likely the " | ||||
"result of an I/O error."); | "result of an I/O error."); | ||||
} | } | ||||
} | } | ||||
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, | static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, | ||||
unsigned int nAddSize); | unsigned int nAddSize); | ||||
▲ Show 20 Lines • Show All 1,808 Lines • ▼ Show 20 Lines | static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, | ||||
if (fKnown) { | if (fKnown) { | ||||
vinfoBlockFile[nFile].nSize = | vinfoBlockFile[nFile].nSize = | ||||
std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); | std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); | ||||
} else { | } else { | ||||
vinfoBlockFile[nFile].nSize += nAddSize; | vinfoBlockFile[nFile].nSize += nAddSize; | ||||
} | } | ||||
if (!fKnown) { | if (!fKnown) { | ||||
unsigned int nOldChunks = | bool out_of_space; | ||||
(pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; | size_t bytes_allocated = | ||||
unsigned int nNewChunks = | BlockFileSeq().Allocate(pos, nAddSize, out_of_space); | ||||
(vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / | if (out_of_space) { | ||||
BLOCKFILE_CHUNK_SIZE; | |||||
if (nNewChunks > nOldChunks) { | |||||
if (fPruneMode) { | |||||
fCheckForPruning = true; | |||||
} | |||||
if (CheckDiskSpace(GetBlocksDir(), | |||||
nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { | |||||
FILE *file = OpenBlockFile(pos); | |||||
if (file) { | |||||
LogPrintf( | |||||
"Pre-allocating up to position 0x%x in blk%05u.dat\n", | |||||
nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); | |||||
AllocateFileRange(file, pos.nPos, | |||||
nNewChunks * BLOCKFILE_CHUNK_SIZE - | |||||
pos.nPos); | |||||
fclose(file); | |||||
} | |||||
} else { | |||||
return AbortNode("Disk space is low!", | return AbortNode("Disk space is low!", | ||||
_("Error: Disk space is low!")); | _("Error: Disk space is low!")); | ||||
} | } | ||||
if (bytes_allocated != 0 && fPruneMode) { | |||||
fCheckForPruning = true; | |||||
} | } | ||||
} | } | ||||
setDirtyFileInfo.insert(nFile); | setDirtyFileInfo.insert(nFile); | ||||
return true; | return true; | ||||
} | } | ||||
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, | static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, | ||||
unsigned int nAddSize) { | unsigned int nAddSize) { | ||||
pos.nFile = nFile; | pos.nFile = nFile; | ||||
LOCK(cs_LastBlockFile); | LOCK(cs_LastBlockFile); | ||||
unsigned int nNewSize; | |||||
pos.nPos = vinfoBlockFile[nFile].nUndoSize; | pos.nPos = vinfoBlockFile[nFile].nUndoSize; | ||||
nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; | vinfoBlockFile[nFile].nUndoSize += nAddSize; | ||||
setDirtyFileInfo.insert(nFile); | setDirtyFileInfo.insert(nFile); | ||||
unsigned int nOldChunks = | bool out_of_space; | ||||
(pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; | size_t bytes_allocated = | ||||
unsigned int nNewChunks = | UndoFileSeq().Allocate(pos, nAddSize, out_of_space); | ||||
(nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; | if (out_of_space) { | ||||
if (nNewChunks > nOldChunks) { | |||||
if (fPruneMode) { | |||||
fCheckForPruning = true; | |||||
} | |||||
if (CheckDiskSpace(GetBlocksDir(), | |||||
nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { | |||||
FILE *file = OpenUndoFile(pos); | |||||
if (file) { | |||||
LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", | |||||
nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); | |||||
AllocateFileRange(file, pos.nPos, | |||||
nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); | |||||
fclose(file); | |||||
} | |||||
} else { | |||||
return AbortNode(state, "Disk space is low!", | return AbortNode(state, "Disk space is low!", | ||||
_("Error: Disk space is low!")); | _("Error: Disk space is low!")); | ||||
} | } | ||||
if (bytes_allocated != 0 && fPruneMode) { | |||||
fCheckForPruning = true; | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Return true if the provided block header is valid. | * Return true if the provided block header is valid. | ||||
* Only verify PoW if blockValidationOptions is configured to do so. | * Only verify PoW if blockValidationOptions is configured to do so. | ||||
▲ Show 20 Lines • Show All 758 Lines • ▼ Show 20 Lines | void PruneOneBlockFile(const int fileNumber) { | ||||
vinfoBlockFile[fileNumber].SetNull(); | vinfoBlockFile[fileNumber].SetNull(); | ||||
setDirtyFileInfo.insert(fileNumber); | setDirtyFileInfo.insert(fileNumber); | ||||
} | } | ||||
void UnlinkPrunedFiles(const std::set<int> &setFilesToPrune) { | void UnlinkPrunedFiles(const std::set<int> &setFilesToPrune) { | ||||
for (const int i : setFilesToPrune) { | for (const int i : setFilesToPrune) { | ||||
CDiskBlockPos pos(i, 0); | CDiskBlockPos pos(i, 0); | ||||
fs::remove(GetBlockPosFilename(pos, "blk")); | fs::remove(BlockFileSeq().FileName(pos)); | ||||
fs::remove(GetBlockPosFilename(pos, "rev")); | fs::remove(UndoFileSeq().FileName(pos)); | ||||
LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, i); | LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, i); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Calculate the block/rev files to delete based on height specified by user | * Calculate the block/rev files to delete based on height specified by user | ||||
* with RPC command pruneblockchain | * with RPC command pruneblockchain | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | static void FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
LogPrint(BCLog::PRUNE, | LogPrint(BCLog::PRUNE, | ||||
"Prune: target=%dMiB actual=%dMiB diff=%dMiB " | "Prune: target=%dMiB actual=%dMiB diff=%dMiB " | ||||
"max_prune_height=%d removed %d blk/rev pairs\n", | "max_prune_height=%d removed %d blk/rev pairs\n", | ||||
nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024, | nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024, | ||||
((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024, | ((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024, | ||||
nLastBlockWeCanPrune, count); | nLastBlockWeCanPrune, count); | ||||
} | } | ||||
static FILE *OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, | static FlatFileSeq BlockFileSeq() { | ||||
bool fReadOnly) { | return FlatFileSeq(GetBlocksDir(), "blk", BLOCKFILE_CHUNK_SIZE); | ||||
if (pos.IsNull()) { | |||||
return nullptr; | |||||
} | |||||
fs::path path = GetBlockPosFilename(pos, prefix); | |||||
fs::create_directories(path.parent_path()); | |||||
FILE *file = fsbridge::fopen(path, fReadOnly ? "rb" : "rb+"); | |||||
if (!file && !fReadOnly) { | |||||
file = fsbridge::fopen(path, "wb+"); | |||||
} | |||||
if (!file) { | |||||
LogPrintf("Unable to open file %s\n", path.string()); | |||||
return nullptr; | |||||
} | |||||
if (pos.nPos) { | |||||
if (fseek(file, pos.nPos, SEEK_SET)) { | |||||
LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, | |||||
path.string()); | |||||
fclose(file); | |||||
return nullptr; | |||||
} | |||||
} | } | ||||
return file; | static FlatFileSeq UndoFileSeq() { | ||||
return FlatFileSeq(GetBlocksDir(), "rev", UNDOFILE_CHUNK_SIZE); | |||||
} | } | ||||
FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { | FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { | ||||
return OpenDiskFile(pos, "blk", fReadOnly); | return BlockFileSeq().Open(pos, fReadOnly); | ||||
} | } | ||||
/** Open an undo file (rev?????.dat) */ | /** Open an undo file (rev?????.dat) */ | ||||
static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { | static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { | ||||
return OpenDiskFile(pos, "rev", fReadOnly); | return UndoFileSeq().Open(pos, fReadOnly); | ||||
} | } | ||||
fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix) { | fs::path GetBlockPosFilename(const CDiskBlockPos &pos) { | ||||
return GetBlocksDir() / strprintf("%s%05u.dat", prefix, pos.nFile); | return BlockFileSeq().FileName(pos); | ||||
} | } | ||||
CBlockIndex *CChainState::InsertBlockIndex(const uint256 &hash) { | CBlockIndex *CChainState::InsertBlockIndex(const uint256 &hash) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (hash.IsNull()) { | if (hash.IsNull()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,318 Lines • Show Last 20 Lines |