Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/fluxnode/fluxnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ bool FluxnodeCache::CheckNewStartTx(const COutPoint& out, int nHeight, bool fFro
void FluxnodeCache::CheckForExpiredStartTx(const int& p_nHeight)
{
LOCK2(cs, g_fluxnodeCache.cs);
if (g_fluxnodeCache.mapStartTxTracker.empty()) {
return;
}
int removalHeight = p_nHeight - FLUXNODE_START_TX_EXPIRATION_HEIGHT;

if (IsPONActive(p_nHeight)) {
Expand Down Expand Up @@ -507,6 +510,9 @@ void FluxnodeCache::CheckForExpiredStartTx(const int& p_nHeight)
void FluxnodeCache::CheckForUndoExpiredStartTx(const int& p_nHeight)
{
LOCK2(cs, g_fluxnodeCache.cs);
if (g_fluxnodeCache.mapStartTxDOSTracker.empty()) {
return;
}
int removalHeight = p_nHeight - FLUXNODE_START_TX_EXPIRATION_HEIGHT;

if (IsPONActive(p_nHeight)) {
Expand Down Expand Up @@ -1809,6 +1815,8 @@ int GetNumberOfTiers()

void FluxnodeCache::LogDebugData(const int& nHeight, const uint256& blockhash, bool fFromDisconnect)
{
if (!LogAcceptCategory("fluxnode")) return;

LOCK(cs);
std::string printme = "{ \n";
for (const auto &printitem: mapStartTxTracker) {
Expand All @@ -1823,10 +1831,10 @@ void FluxnodeCache::LogDebugData(const int& nHeight, const uint256& blockhash, b
printme3 = printme3 + "}";

if (fFromDisconnect) {
LogPrintf("Disconnecting - printing after block=%d, hash=%s\n, mapStart=%s\n\n, mapStartTxDOSTracker=%s\n\n",
LogPrint("fluxnode", "Disconnecting - printing after block=%d, hash=%s\n, mapStart=%s\n\n, mapStartTxDOSTracker=%s\n\n",
nHeight, blockhash.GetHex(), printme, printme3);
} else {
LogPrintf("printing after block=%d, hash=%s\n, mapStart=%s\n\n, mapStartTxDOSTracker=%s\n\n",
LogPrint("fluxnode", "printing after block=%d, hash=%s\n, mapStart=%s\n\n, mapStartTxDOSTracker=%s\n\n",
nHeight, blockhash.GetHex(), printme, printme3);
}

Expand Down
38 changes: 22 additions & 16 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1224,8 +1224,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
// Shrink debug.log on startup if it's too large (configurable, default 500MB) - keeps last 50MB
if (GetBoolArg("-shrinkdebugfile", !fDebug))
// Shrink debug.log on startup if it's too large (configurable, default
// 500 MB, capped at 10 GB). Runs regardless of -debug so the file can't
// grow without bound when debug logging is enabled.
if (GetBoolArg("-shrinkdebugfile", true))
ShrinkDebugFile();

if (fPrintToDebugLog)
Expand Down Expand Up @@ -1474,24 +1476,24 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}

// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
int64_t nBlockTreeDBCache = nTotalCache / 8;
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false))
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB

// https://github.com/bitpay/bitcoin/commit/c91d78b578a8700a45be936cb5bb0931df8f4b87#diff-c865a8939105e6350a50af02766291b7R1233
if (GetBoolArg("-insightexplorer", false)) {
if (!GetBoolArg("-txindex", false)) {
return InitError(_("-insightexplorer requires -txindex."));
}
// increase cache if additional indices are needed
nBlockTreeDBCache = nTotalCache * 3 / 4;
if (GetBoolArg("-insightexplorer", false) && !GetBoolArg("-txindex", false)) {
return InitError(_("-insightexplorer requires -txindex."));
}

// cache size calculations (matches Bitcoin Core's allocation so most of
// -dbcache goes to the in-memory UTXO set during IBD instead of the
// block tree DB)
const bool fHaveBlockTreeIndexes = GetBoolArg("-txindex", false) ||
GetBoolArg("-insightexplorer", false);
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
int64_t nBlockTreeDBCache = std::min(nTotalCache / 8,
(fHaveBlockTreeIndexes ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
nTotalCache -= nBlockTreeDBCache;
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20);
nTotalCache -= nCoinDBCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
LogPrintf("Cache configuration:\n");
Expand Down Expand Up @@ -2069,6 +2071,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing);

// Periodically cap debug.log size. Runs even when -debug is enabled so a
// firehose of debug output can't fill the disk. Interval: 5 minutes.
scheduler.scheduleEvery(&ShrinkDebugFile, 300);

#ifdef ENABLE_MINING
// Generate coins in the background
GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), chainparams);
Expand Down
51 changes: 44 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,35 @@ void FinalizeNode(NodeId nodeid) {
// Remove from high-bandwidth compact block peer list
lNodesAnnouncingHeaderAndIDs.remove(nodeid);

// Clean up any partial compact blocks from this peer
for (auto it = mapPartialBlocks.begin(); it != mapPartialBlocks.end(); ) {
// Note: PartiallyDownloadedBlock doesn't track which peer it came from in current implementation
// This is something we should improve in future iterations
++it;
// Clean up any compact-block in-flight state tied to this peer.
// listCompactBlocksInFlight is the source of truth; mapCompactBlocksInFlight
// is the hash->iterator index. Collect affected block hashes so we can drop
// their partial-block entries once no other peer is still working on them.
std::set<uint256> affectedHashes;
for (auto it = listCompactBlocksInFlight.begin(); it != listCompactBlocksInFlight.end(); ) {
if (it->nodeid == nodeid) {
affectedHashes.insert(it->hash);
auto mapIt = mapCompactBlocksInFlight.find(it->hash);
if (mapIt != mapCompactBlocksInFlight.end() && mapIt->second.first == nodeid) {
mapCompactBlocksInFlight.erase(mapIt);
}
it = listCompactBlocksInFlight.erase(it);
} else {
++it;
}
}
for (const uint256& hash : affectedHashes) {
bool stillInFlight = false;
for (const auto& marker : listCompactBlocksInFlight) {
if (marker.hash == hash) {
stillInFlight = true;
break;
}
}
if (!stillInFlight) {
mapPartialBlocks.erase(hash);
mapPartialBlocksTime.erase(hash);
}
}

mapNodeState.erase(nodeid);
Expand Down Expand Up @@ -6876,6 +6900,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
pcoinsTip->HaveCoins(inv.hash);
}
case MSG_BLOCK:
case MSG_CMPCT_BLOCK:
return mapBlockIndex.count(inv.hash);
}
// Don't know what it is, just say we already got one
Expand All @@ -6902,7 +6927,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
boost::this_thread::interruption_point();
it++;

if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK)
{
bool send = false;
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
Expand Down Expand Up @@ -6934,6 +6959,18 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else if (inv.type == MSG_CMPCT_BLOCK)
{
// BIP 152 low-bandwidth mode: peer-initiated compact block request.
// For older blocks fall back to sending the full block because the
// peer is unlikely to have the mempool state needed to reconstruct.
if (mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
CBlockHeaderAndShortTxIDs cmpctblock(block, false);
pfrom->PushMessage("cmpctblock", cmpctblock);
} else {
pfrom->PushMessage("block", block);
}
}
else // MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
Expand Down Expand Up @@ -7981,7 +8018,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,

// DoS protection: only accept compact blocks that are close to the tip
// This prevents attackers from wasting our CPU/bandwidth with old blocks
if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
if (pindex->nHeight < chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
LogPrint("cmpctblock", "Ignoring compact block from peer %d at height %d (tip is %d)\n",
pfrom->id, pindex->nHeight, chainActive.Height());
return true;
Expand Down
11 changes: 9 additions & 2 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,15 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 4 * 60 * 60;
static const int MAX_UNCONNECTING_HEADERS = 10;
/** Maximum number of compact blocks in flight per block */
static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK = 3;
/** Maximum depth for responding to GETBLOCKTXN requests */
static const int MAX_BLOCKTXN_DEPTH = 10;
/** Maximum depth at which we accept inbound cmpctblock messages or serve
* outbound ones in response to MSG_CMPCT_BLOCK getdata requests.
* Older blocks fall back to a full block because the requester's mempool
* is unlikely to have the transactions needed to reconstruct.
*
* Sized to roughly match Bitcoin Core's ~50-minute wall-clock window.
* Bitcoin Core uses 5 at 10-minute block times; fluxd runs 30-second
* PON blocks, so 100 blocks ≈ 50 minutes. */
static const int MAX_CMPCTBLOCK_DEPTH = 100;
/** Size of extra transaction pool for compact block reconstruction */
static const unsigned int EXTRA_TXNS_FOR_COMPACT_BLOCKS = 100;

Expand Down
4 changes: 2 additions & 2 deletions src/pon/pon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ unsigned int GetNextPONWorkRequired(const CBlockIndex* pindexLast)
// Target timespan = (window - 1) * target spacing (because we're measuring intervals)
int64_t targetTimespan = (lookbackWindow - 1) * params.nPonTargetSpacing;

LogPrintf("PON: Adjustment at height %d: first=%d, last=%d, actualTimespan=%d, targetTimespan=%d\n",
LogPrint("pon", "PON: Adjustment at height %d: first=%d, last=%d, actualTimespan=%d, targetTimespan=%d\n",
nextHeight, pindexFirst->nHeight, pindexLast->nHeight, actualTimespan, targetTimespan);

// Sanity check
Expand Down Expand Up @@ -187,7 +187,7 @@ unsigned int GetNextPONWorkRequired(const CBlockIndex* pindexLast)
newTarget = ponLimit; // Use easiest difficulty as failsafe
}

LogPrintf("PON difficulty adjustment: height=%d, actualTimespan=%d, targetTimespan=%d, before=%08x, after=%08x\n",
LogPrint("pon", "PON difficulty adjustment: height=%d, actualTimespan=%d, targetTimespan=%d, before=%08x, after=%08x\n",
pindexLast->nHeight + 1, actualTimespan, targetTimespan,
pindexLast->nBits, newTarget.GetCompact());

Expand Down
7 changes: 5 additions & 2 deletions src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ static const char* ppszTypeName[] =
"zn quorum",
"zn announce",
"zn ping",
"dstx"
"dstx",
"cmpct block"
};

CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
Expand Down Expand Up @@ -139,7 +140,9 @@ bool CInv::IsKnownType() const

bool CInv::IsFluxnodeType() const
{
return (type >= 4);
// Types 4-10 are Flux-network-specific invs (spork, zn winner, etc).
// MSG_CMPCT_BLOCK (type 11) is not a fluxnode type.
return (type >= 4 && type <= 10);
}

const char* CInv::GetCommand() const
Expand Down
8 changes: 7 additions & 1 deletion src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,13 @@ enum {
MSG_BLOCK,
// Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however,
// MSG_FILTERED_BLOCK should not appear in any invs except as a part of getdata.
MSG_FILTERED_BLOCK
MSG_FILTERED_BLOCK,
// Reserved inv types 4-10 are used for fluxnode-specific invs (see
// ppszTypeName in protocol.cpp).
// BIP 152 low-bandwidth mode: peer-initiated compact block request.
// Diverges from Bitcoin Core's MSG_CMPCT_BLOCK=4 because type 4 is
// already used as "spork" on the Flux network.
MSG_CMPCT_BLOCK = 11,
};

#endif // BITCOIN_PROTOCOL_H
7 changes: 7 additions & 0 deletions src/txdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ static const int64_t nDefaultDbCache = 450;
static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache in (MiB)
static const int64_t nMinDbCache = 4;
//! Max memory allocated to block tree DB specific cache (MiB)
static const int64_t nMaxBlockDBCache = 2;
//! Max memory allocated to block tree DB specific cache, if -txindex or
// insight-explorer indexes are enabled (MiB)
static const int64_t nMaxBlockDBAndTxIndexCache = 1024;
//! Max memory allocated to coin DB specific cache (MiB)
static const int64_t nMaxCoinsDBCache = 8;

struct CDiskTxPos : public CDiskBlockPos
{
Expand Down
69 changes: 43 additions & 26 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,37 +892,54 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {

void ShrinkDebugFile()
{
// Scroll debug.log if it's getting too big
// Scroll debug.log if it's getting too big.
// Safe to call at any time: reads the tail into memory, writes to a temp
// file, and atomically renames over debug.log. Any concurrent LogPrintStr
// writes land on the unlinked inode; LogPrintStr reopens on next call
// when fReopenDebugLog is set.
boost::filesystem::path pathLog = GetDataDir() / "debug.log";
FILE* file = fopen(pathLog.string().c_str(), "r");

// Get configurable size threshold (default 500MB, min 10MB, max 10GB)
int64_t nMaxLogSizeMB = GetArg("-maxdebugfilesize", 500); // Default 500MB
if (nMaxLogSizeMB < 10) nMaxLogSizeMB = 10; // Minimum 10MB
if (nMaxLogSizeMB > 2048) nMaxLogSizeMB = 2048; // Maximum 2GB
// Get configurable size threshold. Default 500 MB, min 10 MB. Upper cap
// depends on whether debug logging is active: 10 GiB with -debug on so a
// long debug session has room to breathe, 2 GiB otherwise.
int64_t nMaxLogSizeMB = GetArg("-maxdebugfilesize", 500);
const int64_t nUpperCapMB = fDebug ? 10240 : 2048;
if (nMaxLogSizeMB < 10) nMaxLogSizeMB = 10;
if (nMaxLogSizeMB > nUpperCapMB) nMaxLogSizeMB = nUpperCapMB;
int64_t nMaxLogSize = nMaxLogSizeMB * 1000000;

if (file && boost::filesystem::file_size(pathLog) > nMaxLogSize)
{
LogPrintf("ShrinkDebugFile: debug.log size is %.1f MB, shrinking to last 50 MB...\n",
boost::filesystem::file_size(pathLog) / 1000000.0);

// Keep last 50MB when shrinking (reasonable amount for debugging)
std::vector <char> vch(50000000,0);
fseek(file, -((long)vch.size()), SEEK_END);
int nBytes = fread(begin_ptr(vch), 1, vch.size(), file);
fclose(file);

file = fopen(pathLog.string().c_str(), "w");
if (file)
{
fwrite(begin_ptr(vch), 1, nBytes, file);
fclose(file);
LogPrintf("ShrinkDebugFile: Shrinking complete, kept %.1f MB\n", nBytes / 1000000.0);
}
boost::system::error_code ec;
uintmax_t curSize = boost::filesystem::file_size(pathLog, ec);
if (ec || (int64_t)curSize <= nMaxLogSize)
return;

// Keep last 50 MB when shrinking.
const size_t nKeepBytes = 50 * 1000 * 1000;

FILE* src = fopen(pathLog.string().c_str(), "rb");
if (!src) return;

std::vector<char> vch(nKeepBytes, 0);
fseek(src, -(long)vch.size(), SEEK_END);
size_t nBytes = fread(begin_ptr(vch), 1, vch.size(), src);
fclose(src);

boost::filesystem::path pathTmp = pathLog;
pathTmp += ".tmp";
FILE* dst = fopen(pathTmp.string().c_str(), "wb");
if (!dst) return;
fwrite(begin_ptr(vch), 1, nBytes, dst);
fclose(dst);

boost::filesystem::rename(pathTmp, pathLog, ec);
if (ec) {
boost::filesystem::remove(pathTmp, ec);
return;
}
else if (file != NULL)
fclose(file);

// Tell LogPrintStr to reopen the log on its next write so future output
// goes to the new (truncated) file instead of the unlinked inode.
fReopenDebugLog = true;
}

#ifdef WIN32
Expand Down
Loading