From 29aaf13b0a99a48ae77cf8a5f765960faa39fb08 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 14 Dec 2015 13:23:45 +0100 Subject: [PATCH 1/5] Make max tip age an option instead of chainparam After discussion in #7164 I think this is better. Max tip age was introduced in #5987 to make it possible to run testnet-in-a-box. But associating this behavior with the testnet chain is wrong conceptually, as it is not needed in normal usage. Should aim to make testnet test the software as-is. Replace it with a (debug) option `-maxtipage`, which can be specified only in the specific case. --- src/chainparams.cpp | 3 --- src/chainparams.h | 2 -- src/init.cpp | 3 +++ src/main.cpp | 5 ++++- src/main.h | 2 ++ 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index d75231ce3..aa346f954 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -115,7 +115,6 @@ public: pchMessageStart[3] = 0x64; vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264"); nDefaultPort = 8233; - nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 100000; const size_t N = 200, K = 9; BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); @@ -275,7 +274,6 @@ public: pchMessageStart[3] = 0xbf; vAlertPubKey = ParseHex("044e7a1553392325c871c5ace5d6ad73501c66f4c185d6b0453cf45dec5a1322e705c672ac1a27ef7cdaf588c10effdf50ed5f95f85f2f54a5f6159fca394ed0c6"); nDefaultPort = 18233; - nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 1000; const size_t N = 200, K = 9; BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); @@ -387,7 +385,6 @@ public: pchMessageStart[2] = 0x3f; pchMessageStart[3] = 0x5f; nDefaultPort = 18344; - nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 1000; const size_t N = 48, K = 5; BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); diff --git a/src/chainparams.h b/src/chainparams.h index f1d9b43c3..df21e57ec 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -68,7 +68,6 @@ public: bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } - int64_t MaxTipAge() const { return nMaxTipAge; } int64_t PruneAfterHeight() const { return nPruneAfterHeight; } unsigned int EquihashN() const { return nEquihashN; } unsigned int EquihashK() const { return nEquihashK; } @@ -97,7 +96,6 @@ protected: //! Raw pub key bytes for the broadcast alert signing key. std::vector vAlertPubKey; int nDefaultPort = 0; - long nMaxTipAge = 0; uint64_t nPruneAfterHeight = 0; unsigned int nEquihashN = 0; unsigned int nEquihashK = 0; diff --git a/src/init.cpp b/src/init.cpp index 2962f3b9a..fe5b50c02 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -472,6 +472,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitfreerelay=", strprintf("Continuously rate-limit free transactions to *1000 bytes per minute (default: %u)", 15)); strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 0)); strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf("Limit size of signature cache to entries (default: %u)", 50000)); + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"), CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK()))); @@ -1077,6 +1078,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-peerbloomfilters", true)) nLocalServices |= NODE_BLOOM; + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + #ifdef ENABLE_MINING if (mapArgs.count("-mineraddress")) { CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); diff --git a/src/main.cpp b/src/main.cpp index 0beb1dd0b..1f1d2037b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,6 +75,9 @@ bool fCoinbaseEnforcedProtectionEnabled = true; size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; +/* If the tip is older than this (in seconds), the node is considered to be in initial block download. + */ +int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; @@ -1733,7 +1736,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); + pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; return state; diff --git a/src/main.h b/src/main.h index 580de352a..201637ab1 100644 --- a/src/main.h +++ b/src/main.h @@ -98,6 +98,7 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; /** Maximum length of reject messages. */ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; +static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; // Sanity check the magic numbers when we change them BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE); @@ -137,6 +138,7 @@ extern bool fCoinbaseEnforcedProtectionEnabled; extern size_t nCoinCacheUsage; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern int64_t nMaxTipAge; /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex *pindexBestHeader; From 02eedeeb693e3105bc6a1ffe26ccd807b51ef5cb Mon Sep 17 00:00:00 2001 From: Kaz Wesley Date: Tue, 26 Apr 2016 17:21:22 -0700 Subject: [PATCH 2/5] IsInitialBlockDownload: usually avoid locking Optimistically test the latch bool before taking the lock. For all IsInitialBlockDownload calls after the first to return false, this avoids the need to lock cs_main. --- src/main.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1f1d2037b..311b35aae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,6 +32,7 @@ #include "wallet/asyncrpcoperation_shieldcoinbase.h" #include +#include #include #include @@ -1727,18 +1728,24 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) bool IsInitialBlockDownload() { const CChainParams& chainParams = Params(); + + // Once this function has returned false, it must remain false. + static std::atomic latchToFalse{false}; + // Optimization: pre-test latch before taking the lock. + if (latchToFalse.load(std::memory_order_relaxed)) + return false; + LOCK(cs_main); + if (latchToFalse.load(std::memory_order_relaxed)) + return false; if (fImporting || fReindex) return true; if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) return true; - static bool lockIBDState = false; - if (lockIBDState) - return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) - lockIBDState = true; + latchToFalse.store(true, std::memory_order_relaxed); return state; } From e41632c9fb5d32491e7f394b7b3a82f6cb5897cb Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sat, 22 Oct 2016 05:33:25 +0000 Subject: [PATCH 3/5] IBD check uses minimumchain work instead of checkpoints. This introduces a 'minimum chain work' chainparam which is intended to be the known amount of work in the chain for the network at the time of software release. If you don't have this much work, you're not yet caught up. This is used instead of the count of blocks test from checkpoints. This criteria is trivial to keep updated as there is no element of subjectivity, trust, or position dependence to it. It is also a more reliable metric of sync status than a block count. --- doc/release-process.md | 2 ++ src/chainparams.cpp | 10 ++++++++++ src/consensus/params.h | 1 + src/main.cpp | 6 ++++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index 93a8e8362..cde355287 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -24,6 +24,8 @@ Check that there are no surprising performance regressions: Ensure that new performance metrics appear on that site. +Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc. + ### Protocol Safety Checks: If this release changes the behavior of the protocol or fixes a serious diff --git a/src/chainparams.cpp b/src/chainparams.cpp index aa346f954..4aa9f8d6b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -106,6 +106,9 @@ public: consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1"); + /** * The message start string should be awesome! ⓩ❤ */ @@ -268,6 +271,9 @@ public: consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000001d0c4d9cd"); + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0x1a; pchMessageStart[2] = 0xf9; @@ -317,6 +323,7 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; + checkpointData = (CCheckpointData) { boost::assign::map_list_of (0, consensus.hashGenesisBlock) @@ -380,6 +387,9 @@ public: consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00"); + pchMessageStart[0] = 0xaa; pchMessageStart[1] = 0xe8; pchMessageStart[2] = 0x3f; diff --git a/src/consensus/params.h b/src/consensus/params.h index 38cf65fb6..c21607046 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -98,6 +98,7 @@ struct Params { int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } + uint256 nMinimumChainWork; }; } // namespace Consensus diff --git a/src/main.cpp b/src/main.cpp index 311b35aae..cc8571b38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1740,7 +1740,9 @@ bool IsInitialBlockDownload() return false; if (fImporting || fReindex) return true; - if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) + if (chainActive.Tip() == NULL) + return true; + if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) return true; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); @@ -1758,7 +1760,7 @@ void CheckForkWarningConditions() { AssertLockHeld(cs_main); // Before we get past initial download, we cannot reliably alert about forks - // (we assume we don't get stuck on a fork before the last checkpoint) + // (we assume we don't get stuck on a fork before finishing our initial sync) if (IsInitialBlockDownload()) return; From f04a90afb202a231e58746a088b58e4980a5b944 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 1 Nov 2016 00:37:54 +0000 Subject: [PATCH 4/5] IsInitialBlockDownload no longer uses header-only timestamps. This avoids a corner case (mostly visible on testnet) where bogus headers can keep nodes in IsInitialBlockDownload. --- src/main.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index cc8571b38..d088369fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1744,11 +1744,10 @@ bool IsInitialBlockDownload() return true; if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) return true; - bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); - if (!state) - latchToFalse.store(true, std::memory_order_relaxed); - return state; + if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) + return true; + latchToFalse.store(true, std::memory_order_relaxed); + return false; } static bool fLargeWorkForkFound = false; From bbff8631f535b2b8e9b06fe4b879609828e2b4d6 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Thu, 11 May 2017 13:11:36 -0400 Subject: [PATCH 5/5] Output line to debug.log when IsInitialBlockDownload latches to false --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index d088369fe..92d80f6a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1746,6 +1746,7 @@ bool IsInitialBlockDownload() return true; if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) return true; + LogPrintf("Leaving InitialBlockDownload (latching to false)\n"); latchToFalse.store(true, std::memory_order_relaxed); return false; }