New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a switch to allow running in a pruned state #4481

Closed
wants to merge 2 commits into
base: master
from
Jump to file or symbol
Failed to load files and symbols.
+130 −41
Diff settings

Always

Just for now

View
@@ -229,6 +229,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -maxorphantx=<n> " + strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS) + "\n";
strUsage += " -par=<n> " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n";
strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n";
strUsage += " -pruned " + _("Run in a pruned state") + "\n";
strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup") + "\n";
#if !defined(WIN32)
strUsage += " -sysperms " + _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)") + "\n";
@@ -593,6 +594,19 @@ bool AppInit2(boost::thread_group& threadGroup)
if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
if (GetBoolArg("-pruned", false)) {
if (GetBoolArg("-txindex", false))
return InitError(_("Pruned mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
if (!GetBoolArg("-disablewallet", false)) {
if (SoftSetBoolArg("-disablewallet", true))
LogPrintf("AppInit2 : parameter interaction: -pruned=1 -> setting -disablewallet=1\n");
else
return InitError(_("Can't run with a wallet in pruned mode."));
}
#endif
}
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = !mapMultiArgs["-debug"].empty();
@@ -631,6 +645,7 @@ bool AppInit2(boost::thread_group& threadGroup)
fPrintToConsole = GetBoolArg("-printtoconsole", false);
fLogTimestamps = GetBoolArg("-logtimestamps", true);
fLogIPs = GetBoolArg("-logips", false);
fPruned = GetBoolArg("-pruned", false);
#ifdef ENABLE_WALLET
bool fDisableWallet = GetBoolArg("-disablewallet", false);
#endif
@@ -960,6 +975,14 @@ bool AppInit2(boost::thread_group& threadGroup)
break;
}
if (!CheckBlockFiles()) {
if (!fPruned)
strLoadError = _("Error checking required block files. You might try to run in -pruned mode, or try to rebuild the block database");
else
strLoadError = _("Error checking required block files");
break;
}
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL)
@@ -1244,6 +1267,8 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
#endif
if (fPruned) // unsetting NODE_NETWORK on pruned state
nLocalServices &= ~NODE_NETWORK;
StartNode(threadGroup);
if (fServer)
StartRPCThreads();
View
@@ -49,6 +49,7 @@ bool fReindex = false;
bool fTxIndex = false;
bool fIsBareMultisigStd = true;
unsigned int nCoinCacheSize = 5000;
bool fPruned = false;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
@@ -2877,24 +2878,6 @@ bool static LoadBlockIndexDB()
if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
LogPrintf("LoadBlockIndexDB(): last block file info: %s\n", infoLastBlockFile.ToString());
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
set<int> setBlkDataFiles;
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
{
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) {
setBlkDataFiles.insert(pindex->nFile);
}
}
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)
{
CDiskBlockPos pos(*it, 0);
if (!CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION)) {
return false;
}
}
// Check whether we need to continue reindexing
bool fReindexing = false;
pblocktree->ReadReindexing(fReindexing);
@@ -2913,7 +2896,75 @@ bool static LoadBlockIndexDB()
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
Checkpoints::GuessVerificationProgress(chainActive.Tip()));
return true;
}
bool CheckBlockFiles()
{
// Check presence of essential data
int nKeepBlksFromHeight = fPruned ? (max((int)(chainActive.Height() - MIN_BLOCKS_TO_KEEP), 0)) : 0;
LogPrintf("Checking all required data for active chain is available (mandatory from height %i to %i)\n", nKeepBlksFromHeight, max(chainActive.Height(), 0));
map<int, bool> mapBlkDataFileReadable,mapBlkUndoFileReadable;
set<int> setBlockDataPruned,setBlockUndoPruned;
for (CBlockIndex* pindex = chainActive.Tip() ; pindex && pindex->pprev ; pindex = pindex->pprev) {
CDiskBlockPos pos(pindex->nFile, 0);
if (pindex->nStatus & BLOCK_HAVE_DATA) {
if (!mapBlkDataFileReadable.count(pindex->nFile)) {
if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION))
mapBlkDataFileReadable[pindex->nFile] = true;
else
if (pindex->nHeight > nKeepBlksFromHeight)
return false;
else
mapBlkDataFileReadable[pindex->nFile] = false;
}
}
else {
if (pindex->nHeight > nKeepBlksFromHeight) {
LogPrintf("Error: Missing block data for block: %i\n", pindex->nHeight);
return false;
}
}
if (pindex->nStatus & BLOCK_HAVE_UNDO) {
if (!mapBlkUndoFileReadable.count(pindex->nFile)) {
if (CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION))
mapBlkUndoFileReadable[pindex->nFile] = true;
else
if (pindex->nHeight > nKeepBlksFromHeight)
return false;
else
mapBlkUndoFileReadable[pindex->nFile] = false;
}
}
else {
if (pindex->nHeight > nKeepBlksFromHeight) {
LogPrintf("Error: Missing undo data for block: %i\n", pindex->nHeight);
return false;
}
}
bool fWrite = false;
if (mapBlkDataFileReadable.count(pindex->nFile) && !mapBlkDataFileReadable.find(pindex->nFile)->second) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
fWrite = true;
}
if (mapBlkUndoFileReadable.count(pindex->nFile) && !mapBlkUndoFileReadable.find(pindex->nFile)->second) {
pindex->nStatus &= ~BLOCK_HAVE_UNDO;
fWrite = true;
}
if (fWrite) {
CDiskBlockIndex blockindex(pindex);
if (!pblocktree->WriteBlockIndex(blockindex))
return false;
}
if(~pindex->nStatus & BLOCK_HAVE_DATA && pindex->nStatus & BLOCK_VALID_CHAIN)
setBlockDataPruned.insert(pindex->nHeight);
if(~pindex->nStatus & BLOCK_HAVE_UNDO && pindex->nStatus & BLOCK_VALID_CHAIN)
setBlockUndoPruned.insert(pindex->nHeight);
}
if(!setBlockDataPruned.empty())
LogPrintf("Data for blocks from %i to %i has been pruned\n", *setBlockDataPruned.begin(), *setBlockDataPruned.end());
if(!setBlockUndoPruned.empty())
LogPrintf("Undo data for blocks from %i to %i has been pruned\n", *setBlockUndoPruned.begin(), *setBlockUndoPruned.end());
return true;
}
@@ -3331,30 +3382,38 @@ void static ProcessGetData(CNode* pfrom)
{
// Send block from disk
CBlock block;
if (!ReadBlockFromDisk(block, (*mi).second))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
{
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
pfrom->PushMessage("merkleblock", merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didnt send here -
// they must either disconnect and retry or request the full block.
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
pfrom->PushMessage("tx", block.vtx[pair.first]);
if (!ReadBlockFromDisk(block, (*mi).second)) {
if (fPruned) {
// Disconnect peers asking us for blocks we don't have, not to stall their IBD. They shouldn't ask as we unset NODE_NETWORK on this mode.
LogPrintf("cannot load block from disk, answering notfound, and disconnecting peer:%d\n", pfrom->id);
vNotFound.push_back(inv);
pfrom->fDisconnect = true;
}
else
AbortNode("cannot load block from disk");
}
else {
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else { // MSG_FILTERED_BLOCK
LOCK(pfrom->cs_filter);
if (pfrom->pfilter) {
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
pfrom->PushMessage("merkleblock", merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
// Note that there is currently no way for a node to request any single transactions we didnt send here -
// they must either disconnect and retry or request the full block.
// Thus, the protocol spec specified allows for us to provide duplicate txn here,
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
pfrom->PushMessage("tx", block.vtx[pair.first]);
}
// else
// no response
}
// else
// no response
}
// Trigger them to send a getblocks request for the next batch of inventory
View
@@ -73,6 +73,8 @@ static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 128;
/** Timeout in seconds before considering a block download peer unresponsive. */
static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60;
/** Minimum amount of blocks to keep unpruned, needed to afford deep reorganizations. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
/** "reject" message codes **/
static const unsigned char REJECT_MALFORMED = 0x01;
@@ -107,6 +109,7 @@ extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee;
extern bool fPruned;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64_t nMinDiskSpace = 52428800;
@@ -152,6 +155,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
bool InitBlockIndex();
/** Load the block tree and coins database from disk */
bool LoadBlockIndex();
/** Check all required block files are present */
bool CheckBlockFiles();
/** Unload database information */
void UnloadBlockIndex();
/** Print the loaded block tree */
ProTip! Use n and p to navigate between commits in a pull request.