Add daemon bootstrap, repeating bootstrap prompt, faster IBD pipeline

- Daemon: add -bootstrap flag to download chain files from server on startup
- Qt: bootstrap prompt shows every launch with "Don't show this again" checkbox
- IBD: reduce pipeline refill interval from 1000 to 100 blocks for faster sync
- Add bootstrap.o to daemon makefiles (mingw + unix)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 21:35:12 -07:00
parent 2abd494fec
commit 47cf8abbda
5 changed files with 83 additions and 8 deletions
+49
View File
@@ -12,6 +12,7 @@
#include "checkpoints.h"
#include "smessage.h"
#include "openssl_compat.h"
#include "bootstrap.h"
#include "tor/tor_embedded.h"
#include "tor/onion_v3.h"
#include "tor/tor_process.h"
@@ -797,6 +798,54 @@ bool AppInit2()
for (string strDest : mapMultiArgs["-seednode"])
AddOneShot(strDest);
// ********************************************************* Step 6b: bootstrap download (daemon)
#ifndef QT_GUI
if (GetBoolArg("-bootstrap", false))
{
fs::path dataPath = GetDataDir();
std::string host = Bootstrap::DEFAULT_HOST;
std::string strError;
std::vector<std::string> files;
uiInterface.InitMessage(_("Fetching bootstrap file list..."));
printf("Bootstrap: contacting %s...\n", host.c_str());
bool fGotList = Bootstrap::FetchFileList(host, files, strError);
if (!fGotList) {
host = Bootstrap::FALLBACK_HOST;
printf("Bootstrap: primary host failed, trying fallback %s...\n", host.c_str());
fGotList = Bootstrap::FetchFileList(host, files, strError);
}
if (!fGotList) {
printf("Bootstrap: could not reach server: %s\n", strError.c_str());
printf("Bootstrap: skipping, will sync from network.\n");
} else {
printf("Bootstrap: downloading %d files...\n", (int)files.size());
for (int i = 0; i < (int)files.size(); i++) {
if (fRequestShutdown) break;
printf("Bootstrap: downloading %s (%d of %d)...\n",
files[i].c_str(), i + 1, (int)files.size());
uiInterface.InitMessage(strprintf(_("Downloading %s (%d of %d)..."),
files[i].c_str(), i + 1, (int)files.size()));
fs::path destPath = dataPath / files[i];
fs::create_directories(destPath.parent_path());
std::string urlPath = std::string(Bootstrap::BASE_PATH) + files[i];
if (!Bootstrap::DownloadFile(host, urlPath, destPath, nullptr, strError)) {
printf("Bootstrap: download failed for %s: %s\n",
files[i].c_str(), strError.c_str());
printf("Bootstrap: will sync remaining data from network.\n");
break;
}
}
printf("Bootstrap: done.\n");
}
}
#endif
// ********************************************************* Step 7: load blockchain
if (!bitdb.Open(GetDataDir()))
+1 -1
View File
@@ -3775,7 +3775,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (IsInitialBlockDownload())
{
static int nBlocksSinceRequest = 0;
if (++nBlocksSinceRequest >= 1000)
if (++nBlocksSinceRequest >= 100)
{
nBlocksSinceRequest = 0;
pfrom->pindexLastGetBlocksBegin = NULL;
+8
View File
@@ -111,6 +111,7 @@ OBJS= \
obj/miner.o \
obj/main.o \
obj/net.o \
obj/bootstrap.o \
obj/net_bootstrap.o \
obj/protocol.o \
obj/trianglesrpc.o \
@@ -232,6 +233,13 @@ obj/tor_embedded.o: tor/tor_embedded.cpp
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
obj/bootstrap.o: bootstrap.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
obj/net_bootstrap.o: net_bootstrap.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
+8
View File
@@ -146,6 +146,7 @@ OBJS= \
obj/miner.o \
obj/main.o \
obj/net.o \
obj/bootstrap.o \
obj/net_bootstrap.o \
obj/protocol.o \
obj/trianglesrpc.o \
@@ -279,6 +280,13 @@ obj/tor_embedded.o: tor/tor_embedded.cpp
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
obj/bootstrap.o: bootstrap.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
obj/net_bootstrap.o: net_bootstrap.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
+17 -7
View File
@@ -11,6 +11,7 @@
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QProgressDialog>
#include <QCheckBox>
#include <QApplication>
#include <boost/filesystem.hpp>
@@ -204,18 +205,27 @@ bool IntroDialog::pickDataDirectory()
return false;
}
// Offer bootstrap download once (tracks via QSettings so it only asks once)
// Offer bootstrap download on each startup (unless user checked "don't ask again")
fs::path dataDirPath(dataDir.toStdString());
if (!settings.value("bootstrapOffered", false).toBool())
if (!settings.value("bootstrapDontAsk", false).toBool())
{
settings.setValue("bootstrapOffered", true);
int ret = QMessageBox::question(0, "Triangles",
QMessageBox msgBox;
msgBox.setWindowTitle("Triangles");
msgBox.setText(
"Would you like to download the latest blockchain snapshot?\n\n"
"This will download the blockchain data from the Triangles network "
"and replace any existing chain data in your data directory.\n\n"
"Click Yes to download, or No to sync from the network.",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
"Click Yes to download, or No to sync from the network.");
msgBox.setIcon(QMessageBox::Question);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
QCheckBox *dontAskBox = new QCheckBox("Don't show this again");
msgBox.setCheckBox(dontAskBox);
int ret = msgBox.exec();
if (dontAskBox->isChecked())
settings.setValue("bootstrapDontAsk", true);
if (ret == QMessageBox::Yes)
{