Skip to content

Commit

Permalink
Redo 2298
Browse files Browse the repository at this point in the history
  • Loading branch information
Liquid369 committed Mar 10, 2023
1 parent 3e2eb99 commit cb07e1d
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 10 deletions.
15 changes: 13 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks");
strUsage += HelpMessageOpt("-reindex", "Rebuild block chain index from current blk000??.dat files on startup");
strUsage += HelpMessageOpt("-resync", "Delete blockchain folders and resync from scratch on startup");
strUsage += HelpMessageOpt("-rewindblockindex", "Rewind blockchain to the last checkpoint");
#if !defined(WIN32)
strUsage += HelpMessageOpt("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)");
#endif
Expand Down Expand Up @@ -1424,6 +1425,7 @@ bool AppInitMain()

fReindex = gArgs.GetBoolArg("-reindex", false);
bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false);
bool clearWitnessCaches = false;

// cache size calculations
int64_t nTotalCache = (gArgs.GetArg("-dbcache", nDefaultDbCache) << 20);
Expand Down Expand Up @@ -1572,8 +1574,17 @@ bool AppInitMain()
}
}

uiInterface.InitMessage(_("Verifying blocks..."));

if (!is_coinsview_empty) {
uiInterface.InitMessage(_("Verifying blocks..."));
if (!fReindex && chainActive.Tip() != NULL) {
uiInterface.InitMessage(_("Rewinding blocks to last checkpoint if needed..."));
if (!RewindBlockIndexToLastCheckpoint(chainparams, clearWitnessCaches, gArgs.GetBoolArg("-rewindblockindex", false))) {
strLoadError = _("Unable to rewind the blockchain to last checkpoint. You will need to redownload the blockchain");
break;
}
}

CBlockIndex *tip = chainActive.Tip();
RPCNotifyBlockChange(true, tip);
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
Expand Down Expand Up @@ -1635,7 +1646,7 @@ bool AppInitMain()

// ********************************************************* Step 8: Backup and Load wallet
#ifdef ENABLE_WALLET
if (!InitLoadWallet())
if (!InitLoadWallet(clearWitnessCaches))
return false;
#else
LogPrintf("No wallet compiled in!\n");
Expand Down
8 changes: 8 additions & 0 deletions src/txdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockF
return WriteBatch(batch, true);
}

bool CBlockTreeDB::EraseBatchSync(const std::vector<const CBlockIndex*>& blockinfo) {
CDBBatch batch;
for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
batch.Erase(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()));
}
return WriteBatch(batch, true);
}

bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos)
{
return Read(std::make_pair(DB_TXINDEX, txid), pos);
Expand Down
1 change: 1 addition & 0 deletions src/txdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class CBlockTreeDB : public CDBWrapper

bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo);
bool EraseBatchSync(const std::vector<const CBlockIndex*>& blockinfo);
bool ReadBlockFileInfo(int nFile, CBlockFileInfo& info);
bool ReadLastBlockFile(int& nFile);
bool WriteReindexing(bool fReindexing);
Expand Down
96 changes: 96 additions & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3741,6 +3741,102 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth
return true;
}

bool RewindBlockIndexToLastCheckpoint(const CChainParams& chainparams, bool& clearWitnessCaches, bool fJustCheck)
{
LOCK(cs_main);

// Get current Height and current Checkpoints
int nHeight = chainActive.Height();
const CBlockIndex* prevCheckPoint = GetLastCheckpoint();
const int checkPointHeight = prevCheckPoint ? prevCheckPoint->nHeight : 0;

// First load options
if(!fJustCheck)
return true;

clearWitnessCaches = true;
CValidationState state;
const int blocksToRollBack = nHeight - checkPointHeight;
// Iterate to start removing blocks
while (nHeight > checkPointHeight) {
if (!DisconnectTip(state, chainparams, nullptr)) {
return error("%s: unable to disconnect block at height %i", __func__, nHeight);
}
// Occasionally flush state to disk.
if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC))
return false;

nHeight = chainActive.Height();
}

// Collect blocks to be removed (blocks in mapBlockIndex must be at least BLOCK_VALID_TREE).
// We do this after actual disconnecting, otherwise we'll end up writing the lack of data
// to disk before writing the chainstate, resulting in a failure to continue if interrupted.
std::vector<const CBlockIndex*> vBlocks;
for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
CBlockIndex* pindexIter = it->second;
if (!chainActive.Contains(pindexIter)) {
// Add to the list of blocks to remove
vBlocks.emplace_back(pindexIter);
if (pindexIter == pindexBestInvalid) {
// Reset invalid block marker if it was pointing to this block
pindexBestInvalid = nullptr;
}
// Reduce validity
pindexIter->nStatus = std::min<unsigned int>(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindexIter->nStatus & ~BLOCK_VALID_MASK);
// Remove have-data flags.
pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
// Remove storage location.
pindexIter->nFile = 0;
pindexIter->nDataPos = 0;
pindexIter->nUndoPos = 0;
// Remove various other things
pindexIter->nTx = 0;
pindexIter->nChainTx = 0;
pindexIter->nSequenceId = 0;
// Update indices
setBlockIndexCandidates.erase(pindexIter);
auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev);
while (ret.first != ret.second) {
if (ret.first->second == pindexIter) {
ret.first = mapBlocksUnlinked.erase(ret.first);
} else {
++ret.first;
}
}
} else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx) {
setBlockIndexCandidates.insert(pindexIter);
}
}

// Set pindexBestHeader to the current chain tip
// (since we are about to delete the block it is pointing to)
pindexBestHeader = chainActive.Tip();

// Erase block indices on-disk
if (!pblocktree->EraseBatchSync(vBlocks)) {
return AbortNode(state, "Failed to erase from block index database");
}

// Erase block indices in-memory
for (auto pindex : vBlocks) {
auto ret = mapBlockIndex.find(*pindex->phashBlock);
if (ret != mapBlockIndex.end()) {
mapBlockIndex.erase(ret);
delete pindex;
}
}

CheckBlockIndex();

if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) {
return false;
}

return true;
}


/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */
static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
Expand Down
3 changes: 3 additions & 0 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ class CVerifyDB
bool VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth);
};

/** Rewind chain up to the last checkpoint */
bool RewindBlockIndexToLastCheckpoint(const CChainParams& chainparams, bool& clearWitnessCaches, bool fJustCheck);

/** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);

Expand Down
4 changes: 2 additions & 2 deletions src/wallet/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ bool WalletVerify()
return true;
}

bool InitLoadWallet()
bool InitLoadWallet(bool clearWitnessCaches)
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
Expand All @@ -214,7 +214,7 @@ bool InitLoadWallet()

for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
// create/load wallet
CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()), clearWitnessCaches);
if (!pwallet) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ bool WalletParameterInteraction();
bool WalletVerify();

//! Load wallet databases.
bool InitLoadWallet();
bool InitLoadWallet(bool clearWitnessCaches);

#endif // PIVX_WALLET_INIT_H
8 changes: 4 additions & 4 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4157,14 +4157,14 @@ void CWallet::LockIfMyCollateral(const CTransactionRef& ptx)
}
}

CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path)
CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path, bool clearWitnessCaches)
{
const std::string& walletFile = name;

// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;

if (gArgs.GetBoolArg("-zapwallettxes", false)) {
if (clearWitnessCaches || gArgs.GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));

std::unique_ptr<CWallet> tempWallet = std::make_unique<CWallet>(name, WalletDatabase::Create(path));
Expand Down Expand Up @@ -4278,7 +4278,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
LOCK(cs_main);
CBlockIndex* pindexRescan = chainActive.Genesis();

if (gArgs.GetBoolArg("-rescan", false)) {
if (clearWitnessCaches || gArgs.GetBoolArg("-rescan", false)) {
// clear note witness cache before a full rescan
walletInstance->ClearNoteWitnessCache();
} else {
Expand Down Expand Up @@ -4326,7 +4326,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
walletInstance->database->IncrementUpdateCounter();

// Restore wallet transaction metadata after -zapwallettxes=1
if (gArgs.GetBoolArg("-zapwallettxes", false) && gArgs.GetArg("-zapwallettxes", "1") != "2") {
if ((clearWitnessCaches || gArgs.GetBoolArg("-zapwallettxes", false)) && gArgs.GetArg("-zapwallettxes", "1") != "2") {
WalletBatch batch(*walletInstance->database);
for (const CWalletTx& wtxOld : vWtx) {
uint256 hash = wtxOld.GetHash();
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
bool AbandonTransaction(const uint256& hashTx);

/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static CWallet* CreateWalletFromFile(const std::string& name, const fs::path& path);
static CWallet* CreateWalletFromFile(const std::string& name, const fs::path& path, bool clearWitnessCaches);

/**
* Wallet post-init setup
Expand Down

0 comments on commit cb07e1d

Please sign in to comment.