Skip to content

Commit 256e66b

Browse files
committed
skip acp during ibd
1 parent 9b7c6da commit 256e66b

4 files changed

Lines changed: 141 additions & 4 deletions

File tree

src/checkpointsync.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <util/system.h>
2121
#include <validation.h>
2222

23+
#include <atomic>
24+
2325
std::string CSyncCheckpoint::strMasterPrivKey;
2426
uint256 hashSyncCheckpoint;
2527
static uint256 hashPendingCheckpoint;
@@ -28,6 +30,7 @@ static CSyncCheckpoint checkpointMessagePending;
2830
RecursiveMutex cs_hashSyncCheckpoint;
2931
CConnman* g_connman{nullptr};
3032
bool fSyncCheckpointsEnabled = DEFAULT_CHECKPOINT_SYNC_ENABLED;
33+
static std::atomic_bool g_reconcile_sync_checkpoint_after_ibd{false};
3134

3235
static bool HasUsableCheckpointChain(const CBlockIndex* pindex)
3336
{
@@ -200,6 +203,126 @@ bool CheckSyncCheckpoint(const uint256& hashBlock, int nHeight, const CBlockInde
200203
return true;
201204
}
202205

206+
void NotifySyncCheckpointIBDExit()
207+
{
208+
g_reconcile_sync_checkpoint_after_ibd = true;
209+
}
210+
211+
static bool ReconcileSyncCheckpointHash(const uint256& hashCheckpoint, bool& switched)
212+
{
213+
switched = false;
214+
215+
CBlockIndex* index = nullptr;
216+
CBlockIndex* bad_fork = nullptr;
217+
{
218+
LOCK2(cs_main, cs_hashSyncCheckpoint);
219+
index = LookupBlockIndex(hashCheckpoint);
220+
if (!HasUsableCheckpointChain(index)) {
221+
return false;
222+
}
223+
if (!::ChainActive().Contains(index)) {
224+
const CBlockIndex* ancestor = LastCommonAncestor(index, ::ChainActive().Tip());
225+
if (ancestor) {
226+
bad_fork = ::ChainActive().Next(ancestor);
227+
}
228+
} else {
229+
return true;
230+
}
231+
}
232+
233+
if (bad_fork && index && index->GetAncestor(bad_fork->nHeight) != bad_fork) {
234+
BlockValidationState state;
235+
InvalidateBlock(state, Params(), bad_fork);
236+
if (state.IsValid() && !::ChainstateActive().ActivateBestChain(state, Params(), nullptr)) {
237+
return error("%s: failed to activate best chain for sync-checkpoint %s (%s)", __func__, hashCheckpoint.ToString(), state.ToString());
238+
}
239+
if (!state.IsValid()) {
240+
return error("%s: failed to switch to sync-checkpoint %s (%s)", __func__, hashCheckpoint.ToString(), state.ToString());
241+
}
242+
}
243+
244+
{
245+
LOCK2(cs_main, cs_hashSyncCheckpoint);
246+
index = LookupBlockIndex(hashCheckpoint);
247+
if (!index || !::ChainActive().Contains(index)) {
248+
return false;
249+
}
250+
}
251+
252+
switched = true;
253+
return true;
254+
}
255+
256+
bool MaybeReconcileSyncCheckpoint()
257+
{
258+
if (!g_reconcile_sync_checkpoint_after_ibd.exchange(false)) {
259+
return true;
260+
}
261+
262+
if (!fSyncCheckpointsEnabled) {
263+
return true;
264+
}
265+
266+
if (::ChainstateActive().IsInitialBlockDownload()) {
267+
g_reconcile_sync_checkpoint_after_ibd = true;
268+
return true;
269+
}
270+
271+
LogPrintf("ACP synchronized checkpoint enforcement enabled after IBD.\n");
272+
273+
uint256 pendingHash;
274+
CSyncCheckpoint pendingMessage;
275+
bool havePending = false;
276+
bool pendingWasActive = false;
277+
{
278+
LOCK2(cs_main, cs_hashSyncCheckpoint);
279+
if (!hashPendingCheckpoint.IsNull() && !checkpointMessagePending.IsNull()) {
280+
pendingHash = hashPendingCheckpoint;
281+
pendingMessage = checkpointMessagePending;
282+
havePending = true;
283+
const CBlockIndex* pendingIndex = LookupBlockIndex(pendingHash);
284+
pendingWasActive = pendingIndex && ::ChainActive().Contains(pendingIndex);
285+
}
286+
}
287+
288+
if (havePending && pendingMessage.ProcessSyncCheckpoint()) {
289+
bool pendingIsActive = false;
290+
{
291+
LOCK2(cs_main, cs_hashSyncCheckpoint);
292+
const CBlockIndex* pendingIndex = LookupBlockIndex(pendingHash);
293+
pendingIsActive = pendingIndex && ::ChainActive().Contains(pendingIndex);
294+
}
295+
if (!pendingWasActive && pendingIsActive) {
296+
LogPrintf("ACP switched to synchronized checkpoint chain %s after IBD.\n", pendingHash.ToString());
297+
}
298+
return true;
299+
}
300+
301+
uint256 currentSyncCheckpoint;
302+
{
303+
LOCK(cs_hashSyncCheckpoint);
304+
currentSyncCheckpoint = hashSyncCheckpoint;
305+
}
306+
307+
bool switched = false;
308+
if (!currentSyncCheckpoint.IsNull() && ReconcileSyncCheckpointHash(currentSyncCheckpoint, switched)) {
309+
if (switched) {
310+
LogPrintf("ACP switched to synchronized checkpoint chain %s after IBD.\n", currentSyncCheckpoint.ToString());
311+
} else if (havePending) {
312+
LogPrintf("ACP enforcement active after IBD, but pending sync-checkpoint %s is not on a usable chain yet.\n", pendingHash.ToString());
313+
}
314+
return true;
315+
}
316+
317+
if (havePending) {
318+
LogPrintf("ACP enforcement active after IBD, but pending sync-checkpoint %s is not on a usable chain yet.\n", pendingHash.ToString());
319+
} else {
320+
LogPrintf("ACP enforcement active after IBD, but no usable synchronized checkpoint branch is available yet.\n");
321+
}
322+
323+
return true;
324+
}
325+
203326
static bool ResetSyncCheckpoint()
204327
{
205328
LOCK(cs_hashSyncCheckpoint);

src/checkpointsync.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ bool CheckSyncCheckpoint(const uint256& hashBlock, int nHeight, const CBlockInde
3636
bool CheckCheckpointPubKey();
3737
bool SetCheckpointPrivKey(const std::string& strPrivKey);
3838
bool SendSyncCheckpoint(const uint256& hashCheckpoint);
39+
void NotifySyncCheckpointIBDExit();
40+
bool MaybeReconcileSyncCheckpoint();
3941

4042
class CUnsignedSyncCheckpoint
4143
{

src/init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,8 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp
758758
}
759759
}
760760

761+
MaybeReconcileSyncCheckpoint();
762+
761763
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
762764
LogPrintf("Stopping after block import\n");
763765
StartShutdown();

src/validation.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,7 +1990,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
19901990
return true;
19911991
}
19921992

1993-
if (!CheckSyncCheckpoint(block.GetHash(), pindex->nHeight)) {
1993+
if (!IsInitialBlockDownload() && !CheckSyncCheckpoint(block.GetHash(), pindex->nHeight)) {
19941994
return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "bad-block-checkpoint-sync");
19951995
}
19961996

@@ -2822,6 +2822,7 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
28222822
CBlockIndex *pindexMostWork = nullptr;
28232823
CBlockIndex *pindexNewTip = nullptr;
28242824
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
2825+
bool fSyncCheckpointIBDExit = false;
28252826
do {
28262827
// Block until the validation queue drains. This should largely
28272828
// never happen in normal operation, however may happen during
@@ -2835,6 +2836,7 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
28352836
LOCK(cs_main);
28362837
LOCK(m_mempool.cs); // Lock transaction pool for at least as long as it takes for connectTrace to be consumed
28372838
CBlockIndex* starting_tip = m_chain.Tip();
2839+
const bool fInitialDownloadOld = IsInitialBlockDownload();
28382840
bool blocks_connected = false;
28392841
do {
28402842
// We absolutely may not unlock cs_main until we've made forward progress
@@ -2873,6 +2875,7 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
28732875

28742876
const CBlockIndex* pindexFork = m_chain.FindFork(starting_tip);
28752877
bool fInitialDownload = IsInitialBlockDownload();
2878+
fSyncCheckpointIBDExit |= fInitialDownloadOld && !fInitialDownload;
28762879

28772880
// Notify external listeners about the new tip.
28782881
// Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
@@ -2894,6 +2897,9 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
28942897
// that the best block hash is non-null.
28952898
if (ShutdownRequested()) break;
28962899
} while (pindexNewTip != pindexMostWork);
2900+
if (fSyncCheckpointIBDExit) {
2901+
NotifySyncCheckpointIBDExit();
2902+
}
28972903
CheckBlockIndex(chainparams.GetConsensus());
28982904

28992905
// Write changes periodically to disk, after relay.
@@ -2905,7 +2911,11 @@ bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainPar
29052911
}
29062912

29072913
bool ActivateBestChain(BlockValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
2908-
return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
2914+
const bool activated = ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
2915+
if (activated) {
2916+
MaybeReconcileSyncCheckpoint();
2917+
}
2918+
return activated;
29092919
}
29102920

29112921
bool CChainState::PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex *pindex)
@@ -3470,7 +3480,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
34703480
if (nHeight > consensusParams.nTimeLimit && block.GetBlockTime() <= pindexPrev->GetBlockTime() - 15 * 60)
34713481
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "wrong-time-between-blocks", "block's timestamp is too early compared to last block");
34723482

3473-
if (!CheckSyncCheckpoint(block.GetHash(), nHeight, pindexPrev))
3483+
if (!::ChainstateActive().IsInitialBlockDownload() && !CheckSyncCheckpoint(block.GetHash(), nHeight, pindexPrev))
34743484
return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "bad-block-checkpoint-sync");
34753485

34763486
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
@@ -3821,7 +3831,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
38213831
NotifyHeaderTip();
38223832

38233833
BlockValidationState state; // Only used to report errors, not invalidity - ignore it
3824-
if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
3834+
if (!ActivateBestChain(state, chainparams, pblock))
38253835
return error("%s: ActivateBestChain failed (%s)", __func__, state.ToString());
38263836

38273837
AcceptPendingSyncCheckpoint();

0 commit comments

Comments
 (0)