Merge pull request #2658 from TheBlueMatt/forkalert
Detect any sufficiently long fork and alert the user just like any other alert
This commit is contained in:
commit
8fa9b5cc45
@ -228,7 +228,7 @@ std::string HelpMessage()
|
|||||||
strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
|
strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
|
||||||
strUsage += " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n";
|
strUsage += " -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n";
|
||||||
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
|
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
|
||||||
strUsage += " -alertnotify=<cmd> " + _("Execute command when a relevant alert is received (%s in cmd is replaced by message)") + "\n";
|
strUsage += " -alertnotify=<cmd> " + _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)") + "\n";
|
||||||
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
|
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
|
||||||
strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
|
strUsage += " -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n";
|
||||||
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
|
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
|
||||||
|
94
src/main.cpp
94
src/main.cpp
@ -1376,6 +1376,82 @@ bool IsInitialBlockDownload()
|
|||||||
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
|
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fLargeWorkForkFound = false;
|
||||||
|
bool fLargeWorkInvalidChainFound = false;
|
||||||
|
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
|
||||||
|
|
||||||
|
void CheckForkWarningConditions()
|
||||||
|
{
|
||||||
|
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
|
||||||
|
// of our head, drop it
|
||||||
|
if (pindexBestForkTip && nBestHeight - pindexBestForkTip->nHeight >= 72)
|
||||||
|
pindexBestForkTip = NULL;
|
||||||
|
|
||||||
|
if (pindexBestForkTip || nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
|
||||||
|
{
|
||||||
|
if (!fLargeWorkForkFound)
|
||||||
|
{
|
||||||
|
std::string strCmd = GetArg("-alertnotify", "");
|
||||||
|
if (!strCmd.empty())
|
||||||
|
{
|
||||||
|
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
|
||||||
|
pindexBestForkBase->phashBlock->ToString() + std::string("'");
|
||||||
|
boost::replace_all(strCmd, "%s", warning);
|
||||||
|
boost::thread t(runCommand, strCmd); // thread runs free
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pindexBestForkTip)
|
||||||
|
{
|
||||||
|
printf("CheckForkWarningConditions: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n",
|
||||||
|
pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString().c_str(),
|
||||||
|
pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString().c_str());
|
||||||
|
fLargeWorkForkFound = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("CheckForkWarningConditions: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n");
|
||||||
|
fLargeWorkInvalidChainFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fLargeWorkForkFound = false;
|
||||||
|
fLargeWorkInvalidChainFound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
|
||||||
|
{
|
||||||
|
// If we are on a fork that is sufficiently large, set a warning flag
|
||||||
|
CBlockIndex* pfork = pindexNewForkTip;
|
||||||
|
CBlockIndex* plonger = pindexBest;
|
||||||
|
while (pfork && pfork != plonger)
|
||||||
|
{
|
||||||
|
while (plonger && plonger->nHeight > pfork->nHeight)
|
||||||
|
plonger = plonger->pprev;
|
||||||
|
if (pfork == plonger)
|
||||||
|
break;
|
||||||
|
pfork = pfork->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We define a condition which we should warn the user about as a fork of at least 7 blocks
|
||||||
|
// who's tip is within 72 blocks (+/- 12 hours if no one mines it) of ours
|
||||||
|
// We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network
|
||||||
|
// hash rate operating on the fork.
|
||||||
|
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both)
|
||||||
|
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets
|
||||||
|
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
|
||||||
|
if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) &&
|
||||||
|
pindexNewForkTip->nChainWork - pfork->nChainWork > (pfork->GetBlockWork() * 7).getuint256() &&
|
||||||
|
nBestHeight - pindexNewForkTip->nHeight < 72)
|
||||||
|
{
|
||||||
|
pindexBestForkTip = pindexNewForkTip;
|
||||||
|
pindexBestForkBase = pfork;
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckForkWarningConditions();
|
||||||
|
}
|
||||||
|
|
||||||
void static InvalidChainFound(CBlockIndex* pindexNew)
|
void static InvalidChainFound(CBlockIndex* pindexNew)
|
||||||
{
|
{
|
||||||
if (pindexNew->nChainWork > nBestInvalidWork)
|
if (pindexNew->nChainWork > nBestInvalidWork)
|
||||||
@ -1391,8 +1467,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
|||||||
printf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n",
|
printf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n",
|
||||||
hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0),
|
hashBestChain.ToString().c_str(), nBestHeight, log(nBestChainWork.getdouble())/log(2.0),
|
||||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
|
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexBest->GetBlockTime()).c_str());
|
||||||
if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
|
CheckForkWarningConditions();
|
||||||
printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void static InvalidBlockFound(CBlockIndex *pindex) {
|
void static InvalidBlockFound(CBlockIndex *pindex) {
|
||||||
@ -2103,11 +2178,14 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
|
|||||||
|
|
||||||
if (pindexNew == pindexBest)
|
if (pindexNew == pindexBest)
|
||||||
{
|
{
|
||||||
|
// Clear fork warning if its no longer applicable
|
||||||
|
CheckForkWarningConditions();
|
||||||
// Notify UI to display prev block's coinbase if it was ours
|
// Notify UI to display prev block's coinbase if it was ours
|
||||||
static uint256 hashPrevBestCoinBase;
|
static uint256 hashPrevBestCoinBase;
|
||||||
UpdatedTransaction(hashPrevBestCoinBase);
|
UpdatedTransaction(hashPrevBestCoinBase);
|
||||||
hashPrevBestCoinBase = block.GetTxHash(0);
|
hashPrevBestCoinBase = block.GetTxHash(0);
|
||||||
}
|
} else
|
||||||
|
CheckForkWarningConditionsOnNewFork(pindexNew);
|
||||||
|
|
||||||
if (!pblocktree->Flush())
|
if (!pblocktree->Flush())
|
||||||
return state.Abort(_("Failed to sync block index"));
|
return state.Abort(_("Failed to sync block index"));
|
||||||
@ -3066,11 +3144,15 @@ string GetWarnings(string strFor)
|
|||||||
strStatusBar = strMiscWarning;
|
strStatusBar = strMiscWarning;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Longer invalid proof-of-work chain
|
if (fLargeWorkForkFound)
|
||||||
if (pindexBest && nBestInvalidWork > nBestChainWork + (pindexBest->GetBlockWork() * 6).getuint256())
|
|
||||||
{
|
{
|
||||||
nPriority = 2000;
|
nPriority = 2000;
|
||||||
strStatusBar = strRPC = _("Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.");
|
strStatusBar = strRPC = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
|
||||||
|
}
|
||||||
|
else if (fLargeWorkInvalidChainFound)
|
||||||
|
{
|
||||||
|
nPriority = 2000;
|
||||||
|
strStatusBar = strRPC = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alerts
|
// Alerts
|
||||||
|
Loading…
Reference in New Issue
Block a user