Skip to content

Commit c271304

Browse files
committed
Merge pull request #5863
f9ec3f0 Add block pruning functionality (mrbandrews)
2 parents 734f80a + f9ec3f0 commit c271304

File tree

7 files changed

+744
-37
lines changed

7 files changed

+744
-37
lines changed

qa/rpc-tests/pruning.py

Lines changed: 356 additions & 0 deletions
Large diffs are not rendered by default.

qa/rpc-tests/util.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def _rpchost_to_args(rpchost):
158158
rv += ['-rpcport=' + rpcport]
159159
return rv
160160

161-
def start_node(i, dirname, extra_args=None, rpchost=None):
161+
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None):
162162
"""
163163
Start a bitcoind and return RPC connection to it
164164
"""
@@ -172,7 +172,10 @@ def start_node(i, dirname, extra_args=None, rpchost=None):
172172
["-rpcwait", "getblockcount"], stdout=devnull)
173173
devnull.close()
174174
url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
175-
proxy = AuthServiceProxy(url)
175+
if timewait is not None:
176+
proxy = AuthServiceProxy(url, timeout=timewait)
177+
else:
178+
proxy = AuthServiceProxy(url)
176179
proxy.url = url # store URL on proxy for info
177180
return proxy
178181

src/chainparams.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ class CMainParams : public CChainParams {
121121
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
122122
nDefaultPort = 8333;
123123
nMinerThreads = 0;
124+
nPruneAfterHeight = 100000;
124125

125126
/**
126127
* Build the genesis block. Note that the output of the genesis coinbase cannot
@@ -198,6 +199,7 @@ class CTestNetParams : public CMainParams {
198199
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
199200
nDefaultPort = 18333;
200201
nMinerThreads = 0;
202+
nPruneAfterHeight = 1000;
201203

202204
//! Modify the testnet genesis block so the timestamp is valid for a later start.
203205
genesis.nTime = 1296688602;
@@ -257,6 +259,7 @@ class CRegTestParams : public CTestNetParams {
257259
consensus.hashGenesisBlock = genesis.GetHash();
258260
nDefaultPort = 18444;
259261
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
262+
nPruneAfterHeight = 1000;
260263

261264
vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
262265
vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds.

src/chainparams.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class CChainParams
5858
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
5959
/** Make standard checks */
6060
bool RequireStandard() const { return fRequireStandard; }
61+
int64_t PruneAfterHeight() const { return nPruneAfterHeight; }
6162
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
6263
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
6364
/** In the future use NetworkIDString() for RPC fields */
@@ -77,6 +78,7 @@ class CChainParams
7778
std::vector<unsigned char> vAlertPubKey;
7879
int nDefaultPort;
7980
int nMinerThreads;
81+
uint64_t nPruneAfterHeight;
8082
std::vector<CDNSSeedData> vSeeds;
8183
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
8284
std::string strNetworkID;

src/init.cpp

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ std::string HelpMessage(HelpMessageMode mode)
275275
#ifndef WIN32
276276
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "bitcoind.pid"));
277277
#endif
278-
strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup"));
278+
strUsage += HelpMessageOpt("-prune=<n>", _("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex.") + " " +
279+
_("Warning: Reverting this setting requires re-downloading the entire blockchain.") + " " +
280+
_("(default: 0 = disable pruning blocks,") + " " +
281+
strprintf(_(">%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
282+
strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup"));
283+
279284
#if !defined(WIN32)
280285
strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)"));
281286
#endif
@@ -352,7 +357,7 @@ std::string HelpMessage(HelpMessageMode mode)
352357
strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1));
353358
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0));
354359
}
355-
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy"; // Don't translate these and qt below
360+
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below
356361
if (mode == HMM_BITCOIN_QT)
357362
debugCategories += ", qt";
358363
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -458,10 +463,33 @@ struct CImportingNow
458463
}
459464
};
460465

466+
467+
// If we're using -prune with -reindex, then delete block files that will be ignored by the
468+
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
469+
// is missing, and since pruning works by deleting the oldest block file first, just check
470+
// for block file 0, and if it doesn't exist, delete all the block files in the
471+
// directory (since they won't be read by the reindex but will take up disk space).
472+
void DeleteAllBlockFiles()
473+
{
474+
if (boost::filesystem::exists(GetBlockPosFilename(CDiskBlockPos(0, 0), "blk")))
475+
return;
476+
477+
LogPrintf("Removing all blk?????.dat and rev?????.dat files for -reindex with -prune\n");
478+
boost::filesystem::path blocksdir = GetDataDir() / "blocks";
479+
for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) {
480+
if (is_regular_file(*it)) {
481+
if ((it->path().filename().string().length() == 12) &&
482+
(it->path().filename().string().substr(8,4) == ".dat") &&
483+
((it->path().filename().string().substr(0,3) == "blk") ||
484+
(it->path().filename().string().substr(0,3) == "rev")))
485+
boost::filesystem::remove(it->path());
486+
}
487+
}
488+
}
489+
461490
void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
462491
{
463492
RenameThread("bitcoin-loadblk");
464-
465493
// -reindex
466494
if (fReindex) {
467495
CImportingNow imp;
@@ -674,6 +702,21 @@ bool AppInit2(boost::thread_group& threadGroup)
674702
if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
675703
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
676704

705+
// if using block pruning, then disable txindex
706+
// also disable the wallet (for now, until SPV support is implemented in wallet)
707+
if (GetArg("-prune", 0)) {
708+
if (GetBoolArg("-txindex", false))
709+
return InitError(_("Prune mode is incompatible with -txindex."));
710+
#ifdef ENABLE_WALLET
711+
if (!GetBoolArg("-disablewallet", false)) {
712+
if (SoftSetBoolArg("-disablewallet", true))
713+
LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__);
714+
else
715+
return InitError(_("Can't run with a wallet in prune mode."));
716+
}
717+
#endif
718+
}
719+
677720
// ********************************************************* Step 3: parameter-to-internal-flags
678721

679722
fDebug = !mapMultiArgs["-debug"].empty();
@@ -710,6 +753,21 @@ bool AppInit2(boost::thread_group& threadGroup)
710753
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
711754

712755
fServer = GetBoolArg("-server", false);
756+
757+
// block pruning; get the amount of disk space (in MB) to allot for block & undo files
758+
int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
759+
if (nSignedPruneTarget < 0) {
760+
return InitError(_("Prune cannot be configured with a negative value."));
761+
}
762+
nPruneTarget = (uint64_t) nSignedPruneTarget;
763+
if (nPruneTarget) {
764+
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
765+
return InitError(strprintf(_("Prune configured below the minimum of %d MB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
766+
}
767+
LogPrintf("Prune configured to target %uMiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
768+
fPruneMode = true;
769+
}
770+
713771
#ifdef ENABLE_WALLET
714772
bool fDisableWallet = GetBoolArg("-disablewallet", false);
715773
#endif
@@ -1030,8 +1088,12 @@ bool AppInit2(boost::thread_group& threadGroup)
10301088
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
10311089
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
10321090

1033-
if (fReindex)
1091+
if (fReindex) {
10341092
pblocktree->WriteReindexing(true);
1093+
//If we're reindexing in prune mode, wipe away all our block and undo data files
1094+
if (fPruneMode)
1095+
DeleteAllBlockFiles();
1096+
}
10351097

10361098
if (!LoadBlockIndex()) {
10371099
strLoadError = _("Error loading block database");
@@ -1055,7 +1117,18 @@ bool AppInit2(boost::thread_group& threadGroup)
10551117
break;
10561118
}
10571119

1120+
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
1121+
// in the past, but is now trying to run unpruned.
1122+
if (fHavePruned && !fPruneMode) {
1123+
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
1124+
break;
1125+
}
1126+
10581127
uiInterface.InitMessage(_("Verifying blocks..."));
1128+
if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) {
1129+
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
1130+
MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288));
1131+
}
10591132
if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3),
10601133
GetArg("-checkblocks", 288))) {
10611134
strLoadError = _("Corrupted block database detected");
@@ -1106,6 +1179,15 @@ bool AppInit2(boost::thread_group& threadGroup)
11061179
mempool.ReadFeeEstimates(est_filein);
11071180
fFeeEstimatesInitialized = true;
11081181

1182+
// if prune mode, unset NODE_NETWORK and prune block files
1183+
if (fPruneMode) {
1184+
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
1185+
nLocalServices &= ~NODE_NETWORK;
1186+
if (!fReindex) {
1187+
PruneAndFlush();
1188+
}
1189+
}
1190+
11091191
// ********************************************************* Step 8: load wallet
11101192
#ifdef ENABLE_WALLET
11111193
if (fDisableWallet) {

0 commit comments

Comments
 (0)