Anti-fork hardening: faster convergence for small Tor-only network (v5.8.3)
Build All Platforms / test-linux-unit (push) Failing after 40s
Build All Platforms / build-linux-qt (push) Failing after 40s
Build All Platforms / build-linux-daemon (push) Failing after 40s
Build All Platforms / build-windows-qt (push) Has been cancelled
Build All Platforms / build-windows-daemon (push) Has been cancelled
Build All Platforms / build-macos (push) Has been cancelled
Build All Platforms / release (push) Has been cancelled
Build All Platforms / Trigger TRI-PI ARM64 Build (push) Has been cancelled
Build All Platforms / test-linux-unit (push) Failing after 40s
Build All Platforms / build-linux-qt (push) Failing after 40s
Build All Platforms / build-linux-daemon (push) Failing after 40s
Build All Platforms / build-windows-qt (push) Has been cancelled
Build All Platforms / build-windows-daemon (push) Has been cancelled
Build All Platforms / build-macos (push) Has been cancelled
Build All Platforms / release (push) Has been cancelled
Build All Platforms / Trigger TRI-PI ARM64 Build (push) Has been cancelled
- Reduce equal-trust reorg cooldown from 10min to 2min for faster convergence - Tighten future block drift from 3min to 90sec to shrink competing-block window - Require 2+ peers before staking (was 1) to prevent isolated fork creation - Push full blocks directly to peers instead of inv-only (saves 1-2s Tor roundtrip) - Add periodic 45-second chain-tip sync to detect and resolve silent forks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ if(POLICY CMP0167)
|
||||
endif()
|
||||
|
||||
project(Triangles
|
||||
VERSION 5.8.2
|
||||
VERSION 5.8.3
|
||||
DESCRIPTION "Cryptographic Triangles Wallet"
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 5
|
||||
#define CLIENT_VERSION_MINOR 8
|
||||
#define CLIENT_VERSION_REVISION 2
|
||||
#define CLIENT_VERSION_REVISION 3
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Converts the parameter X to a string after macro replacement on X has been performed.
|
||||
|
||||
+25
-5
@@ -2970,15 +2970,15 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u
|
||||
// 2. Equal trust: deterministic hash tiebreaker — lower tip hash wins.
|
||||
// This ensures all nodes converge on the same chain even when two
|
||||
// forks have identical cumulative difficulty (common in PoS).
|
||||
// Rate-limited to one equal-trust reorg per 10 minutes to prevent
|
||||
// oscillation from Tor-latency-induced competing announcements.
|
||||
// Rate-limited to one equal-trust reorg per 2 minutes — short enough
|
||||
// for fast convergence but long enough to prevent oscillation on Tor.
|
||||
bool fNewBest = false;
|
||||
static int64_t nLastEqualTrustReorg = 0;
|
||||
if (pindexNew->nChainTrust > nBestChainTrust)
|
||||
fNewBest = true;
|
||||
else if (pindexNew->nChainTrust == nBestChainTrust && pindexBest &&
|
||||
pindexNew->GetBlockHash() < pindexBest->GetBlockHash() &&
|
||||
GetTime() - nLastEqualTrustReorg > 10 * 60)
|
||||
GetTime() - nLastEqualTrustReorg > 2 * 60)
|
||||
{
|
||||
fNewBest = true;
|
||||
nLastEqualTrustReorg = GetTime();
|
||||
@@ -3190,14 +3190,20 @@ bool CBlock::AcceptBlock()
|
||||
if (!AddToBlockIndex(nFile, nBlockPos, hashProofOfStake))
|
||||
return error("AcceptBlock() : AddToBlockIndex failed");
|
||||
|
||||
// Relay inventory, but don't relay old inventory during initial block download
|
||||
// Push new tip block directly to all peers. On a small Tor-only
|
||||
// network the inv→getdata→block round-trip adds 1-2 seconds of latency
|
||||
// per hop — enough for a competing staker to create a fork. Pushing
|
||||
// the full block immediately cuts propagation to a single hop.
|
||||
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
|
||||
if (hashBestChain == hash)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (CNode* pnode : vNodes)
|
||||
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
||||
pnode->PushInventory(CInv(MSG_BLOCK, hash));
|
||||
{
|
||||
pnode->PushMessage("block", *this);
|
||||
pnode->AddInventoryKnown(CInv(MSG_BLOCK, hash));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -5308,6 +5314,20 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
pto->PushMessage("inv", vInv);
|
||||
|
||||
|
||||
//
|
||||
// Periodic chain-tip sync: every 45 seconds, ask each peer if they
|
||||
// have blocks we don't. On a small Tor-only network, transient
|
||||
// partitions can cause forks that persist silently — this ensures
|
||||
// nodes discover the longer chain even without explicit announcement.
|
||||
//
|
||||
if (!IsInitialBlockDownload() && !pto->fClient && pindexBest &&
|
||||
GetTime() - pto->nLastTipCheck > 45)
|
||||
{
|
||||
pto->nLastTipCheck = GetTime();
|
||||
pto->pindexLastGetBlocksBegin = NULL; // reset dedup to force request
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
}
|
||||
|
||||
//
|
||||
// Stall detection: if we're still catching up and no new blocks for
|
||||
// a while, re-request. Active during IBD (5s timeout) and also
|
||||
|
||||
+2
-2
@@ -59,10 +59,10 @@ static const int fHaveUPnP = false;
|
||||
|
||||
static const uint256 hashGenesisBlockOfficial("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||
static const uint256 hashGenesisBlockTestNet ("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||
inline int64_t GetMaxTimeDrift(int nHeight) { return (nHeight >= FORK_HEIGHT_V5_4) ? 3 * 60 : 10 * 60; }
|
||||
inline int64_t GetMaxTimeDrift(int nHeight) { return (nHeight >= FORK_HEIGHT_V5_4) ? 90 : 10 * 60; }
|
||||
inline int64_t PastDrift(int64_t nTime, int nHeight) { return nTime - GetMaxTimeDrift(nHeight); }
|
||||
inline int64_t FutureDrift(int64_t nTime, int nHeight) { return nTime + GetMaxTimeDrift(nHeight); }
|
||||
// Height-less overloads always use post-V5.4 rules (3-min drift).
|
||||
// Height-less overloads always use post-V5.4 rules (90-second drift).
|
||||
// All nodes are well past FORK_HEIGHT_V5_4; using the global nBestHeight
|
||||
// here previously caused nodes at different heights to disagree on block
|
||||
// validity during the fork transition — a consensus-splitting bug.
|
||||
|
||||
+1
-1
@@ -413,7 +413,7 @@ void StakeMiner(CWallet *pwallet)
|
||||
if (fTryToSync)
|
||||
{
|
||||
fTryToSync = false;
|
||||
if (vNodes.size() < 1 || nBestHeight < GetNumBlocksOfPeers())
|
||||
if (vNodes.size() < 2 || nBestHeight < GetNumBlocksOfPeers())
|
||||
{
|
||||
MilliSleep(60000);
|
||||
continue;
|
||||
|
||||
@@ -272,6 +272,7 @@ public:
|
||||
CBlockIndex* pindexLastGetHeadersBegin;
|
||||
uint256 hashLastGetHeadersEnd;
|
||||
int nStartingHeight;
|
||||
int64_t nLastTipCheck; // last time we asked this peer for chain tip
|
||||
|
||||
// flood relay
|
||||
std::vector<CAddress> vAddrToSend;
|
||||
@@ -319,6 +320,7 @@ public:
|
||||
pindexLastGetHeadersBegin = 0;
|
||||
hashLastGetHeadersEnd = 0;
|
||||
nStartingHeight = -1;
|
||||
nLastTipCheck = 0;
|
||||
fGetAddr = false;
|
||||
nMisbehavior = 0;
|
||||
hashCheckpointKnown = 0;
|
||||
|
||||
Reference in New Issue
Block a user