Skip to content

Commit 8676337

Browse files
committed
Implement -reindex option
This PR adds to the GRC::Upgrade utility class and implements the wallet -reindex startup parameter.
1 parent 319a234 commit 8676337

File tree

5 files changed

+248
-43
lines changed

5 files changed

+248
-43
lines changed

src/gridcoin/upgrade.cpp

Lines changed: 132 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -485,9 +485,9 @@ void Upgrade::VerifySHA256SUM()
485485
}
486486
}
487487

488-
void Upgrade::CleanupBlockchainData()
488+
bool Upgrade::GetActualCleanupPath(fs::path& actual_cleanup_path)
489489
{
490-
fs::path CleanupPath = GetDataDir();
490+
actual_cleanup_path = GetDataDir();
491491

492492
// This is required because of problems with junction point handling in the boost filesystem library. Please see
493493
// https://github.com/boostorg/filesystem/issues/125. We are not quite ready to switch over to std::filesystem yet.
@@ -496,16 +496,16 @@ void Upgrade::CleanupBlockchainData()
496496
//
497497
// I don't believe it is very common for Windows users to redirect the Gridcoin data directory with a junction point,
498498
// but it is certainly possible. We should handle it as gracefully as possible.
499-
if (fs::is_symlink(CleanupPath))
499+
if (fs::is_symlink(actual_cleanup_path))
500500
{
501501
LogPrintf("INFO: %s: Data directory is a symlink.",
502502
__func__);
503503

504504
try
505505
{
506-
LogPrintf("INFO: %s: True path for the symlink is %s.", __func__, fs::read_symlink(CleanupPath).string());
506+
LogPrintf("INFO: %s: True path for the symlink is %s.", __func__, fs::read_symlink(actual_cleanup_path).string());
507507

508-
CleanupPath = fs::read_symlink(CleanupPath);
508+
actual_cleanup_path = fs::read_symlink(actual_cleanup_path);
509509
}
510510
catch (fs::filesystem_error &ex)
511511
{
@@ -515,10 +515,19 @@ void Upgrade::CleanupBlockchainData()
515515

516516
DownloadStatus.SetCleanupBlockchainDataFailed(true);
517517

518-
return;
518+
return false;
519519
}
520520
}
521521

522+
return true;
523+
}
524+
525+
void Upgrade::CleanupBlockchainData(bool include_blockchain_data_files)
526+
{
527+
fs::path CleanupPath;
528+
529+
if (!GetActualCleanupPath(CleanupPath)) return;
530+
522531
unsigned int total_items = 0;
523532
unsigned int items = 0;
524533

@@ -559,7 +568,7 @@ void Upgrade::CleanupBlockchainData()
559568
continue;
560569
}
561570

562-
else if (fs::is_regular_file(*Iter))
571+
else if (fs::is_regular_file(*Iter) && include_blockchain_data_files)
563572
{
564573
size_t FileLoc = Iter->path().filename().string().find("blk");
565574

@@ -648,7 +657,7 @@ void Upgrade::CleanupBlockchainData()
648657
continue;
649658
}
650659

651-
else if (fs::is_regular_file(*Iter))
660+
else if (fs::is_regular_file(*Iter) && include_blockchain_data_files)
652661
{
653662
size_t FileLoc = Iter->path().filename().string().find("blk");
654663

@@ -875,13 +884,126 @@ void Upgrade::DeleteSnapshot()
875884
}
876885
}
877886

878-
bool Upgrade::ResetBlockchainData()
887+
bool Upgrade::ResetBlockchainData(bool include_blockchain_data_files)
879888
{
880-
CleanupBlockchainData();
889+
CleanupBlockchainData(include_blockchain_data_files);
881890

882891
return (DownloadStatus.GetCleanupBlockchainDataComplete() && !DownloadStatus.GetCleanupBlockchainDataFailed());
883892
}
884893

894+
bool Upgrade::MoveBlockDataFiles(std::set<std::pair<fs::path, uintmax_t>>& block_data_files)
895+
{
896+
fs::path cleanup_path;
897+
898+
if (!GetActualCleanupPath(cleanup_path)) return false;
899+
900+
fs::directory_iterator IterEnd;
901+
902+
try {
903+
for (fs::directory_iterator Iter(cleanup_path); Iter != IterEnd; ++Iter) {
904+
if (fs::is_regular_file(*Iter)) {
905+
size_t FileLoc = Iter->path().filename().string().find("blk");
906+
907+
if (FileLoc != std::string::npos) {
908+
std::string filetocheck = Iter->path().filename().string();
909+
910+
// Check it ends with .dat and starts with blk
911+
if (filetocheck.substr(0, 3) == "blk" && filetocheck.substr(filetocheck.length() - 4, 4) == ".dat") {
912+
fs::path new_name = *Iter;
913+
new_name.replace_extension(".dat.orig");
914+
915+
uintmax_t file_size = fs::file_size(Iter->path());
916+
917+
// Rename with orig as the extension, because ProcessBlock will load blocks into a new block data
918+
// file.
919+
fs::rename(*Iter, new_name);
920+
block_data_files.insert(std::make_pair(new_name, file_size));
921+
}
922+
}
923+
}
924+
}
925+
} catch (fs::filesystem_error &ex) {
926+
error("%s: Exception occurred: %s. Failed to rename block data files to blk*.dat.orig in preparation for "
927+
"reindexing.", __func__, ex.what());
928+
929+
return false;
930+
}
931+
932+
return true;
933+
}
934+
935+
bool Upgrade::ReindexBlockchainData(std::set<std::pair<fs::path, uintmax_t>>& block_data_files)
936+
{
937+
bool successful = true;
938+
939+
uintmax_t total_size = 0;
940+
uintmax_t cumulative_size = 0;
941+
942+
for (const auto& iter : block_data_files) {
943+
total_size += iter.second;
944+
}
945+
946+
if (!total_size) return false;
947+
948+
try {
949+
for (const auto& iter : block_data_files) {
950+
951+
unsigned int percent_start = cumulative_size * (uintmax_t) 100 / total_size;
952+
953+
cumulative_size += iter.second;
954+
955+
unsigned int percent_end = cumulative_size * (uintmax_t) 100 / total_size;
956+
957+
FILE *block_data_file = fsbridge::fopen(iter.first, "rb");
958+
959+
LogPrintf("INFO: %s: Loading blocks from %s.", __func__, iter.first.filename().string());
960+
961+
if (!LoadExternalBlockFile(block_data_file, iter.second, percent_start, percent_end)) {
962+
successful = false;
963+
964+
break;
965+
}
966+
}
967+
} catch (fs::filesystem_error &ex) {
968+
error("%s: Exception occurred: %s. Failure occurred during attempt to load blocks from original "
969+
"block data file(s).", __func__, ex.what());
970+
971+
successful = false;
972+
}
973+
974+
if (successful) {
975+
try {
976+
fs::path cleanup_path;
977+
978+
if (!GetActualCleanupPath(cleanup_path)) return false;
979+
980+
for (const auto& iter : block_data_files) {
981+
if (!fs::remove(iter.first)) {
982+
LogPrintf("WARN: %s: Reindexing of the blockchain was successful; however, one or more of "
983+
"the original block data files (%s) was not able to be deleted. You "
984+
"will have to delete this file manually.", __func__, iter.first.filename().string());
985+
}
986+
}
987+
}
988+
catch (fs::filesystem_error &ex) {
989+
LogPrintf("WARN: %s: Exception occurred: %s. This error occurred while attempting to delete the original block "
990+
"data files (blk*.dat.orig). You will have to delete these manually.", __func__, ex.what());
991+
}
992+
} else {
993+
error("%s: A failure occurred during the reindexing of the block data files. The blockchain state is invalid and "
994+
"you should restart the wallet with the -resetblockchaindata option to clear out the blockchain database "
995+
"and re-sync the blockchain from the network.", __func__);
996+
997+
DownloadStatus.SetCleanupBlockchainDataFailed(true);
998+
999+
return false;
1000+
}
1001+
1002+
LogPrintf("INFO: %s: Reindex of the blockchain data was successful.", __func__);
1003+
1004+
return true;
1005+
}
1006+
8851007
std::string Upgrade::ResetBlockchainMessages(ResetBlockchainMsg _msg)
8861008
{
8871009
std::stringstream stream;

src/gridcoin/upgrade.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sstream>
1111
#include <iomanip>
1212
#include <vector>
13+
#include <set>
1314

1415
#include "gridcoin/scraper/http.h"
1516
#include "node/ui_interface.h"
@@ -140,12 +141,19 @@ class Upgrade
140141
//!
141142
static void DownloadSnapshot();
142143

144+
//!
145+
//! \brief Resolves symlinks to the actual path.
146+
//! \param actual_cleanup_path is the resolved path
147+
//! \return
148+
//!
149+
static bool GetActualCleanupPath(fs::path& actual_cleanup_path);
150+
143151
//!
144152
//! \brief Cleans up previous blockchain data if any is found
145153
//!
146154
//! \return Bool on the success of cleanup
147155
//!
148-
static void CleanupBlockchainData();
156+
static void CleanupBlockchainData(bool include_blockchain_data_files = true);
149157

150158
//!
151159
//! \brief This is the worker thread "main" that actually does the brunt of the snapshot download and extraction work.
@@ -183,8 +191,20 @@ class Upgrade
183191
//!
184192
//! \returns Bool on the success of blockchain cleanup
185193
//!
186-
static bool ResetBlockchainData();
194+
static bool ResetBlockchainData(bool include_blockchain_data_files = true);
195+
196+
//!
197+
//! \brief Moves the block data files from .dat to .dat.orig in preparation for reindexing.
198+
//! \return
199+
//!
200+
static bool MoveBlockDataFiles(std::set<std::pair<fs::path, uintmax_t> > &block_data_files);
187201

202+
//!
203+
//! \brief Utility function to support the -reindex startup parameter to rebuild txleveldb and accrual from
204+
//! existing blockchain data files.
205+
//! \return
206+
//!
207+
static bool ReindexBlockchainData(std::set<std::pair<fs::path, uintmax_t> > &block_data_files);
188208
//!
189209
//! \brief Small function to return translated messages.
190210
//!

0 commit comments

Comments
 (0)