2020#include < util/system.h>
2121#include < validation.h>
2222
23+ #include < atomic>
24+
2325std::string CSyncCheckpoint::strMasterPrivKey;
2426uint256 hashSyncCheckpoint;
2527static uint256 hashPendingCheckpoint;
@@ -28,6 +30,7 @@ static CSyncCheckpoint checkpointMessagePending;
2830RecursiveMutex cs_hashSyncCheckpoint;
2931CConnman* g_connman{nullptr };
3032bool fSyncCheckpointsEnabled = DEFAULT_CHECKPOINT_SYNC_ENABLED ;
33+ static std::atomic_bool g_reconcile_sync_checkpoint_after_ibd{false };
3134
3235static 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+
203326static bool ResetSyncCheckpoint ()
204327{
205328 LOCK (cs_hashSyncCheckpoint);
0 commit comments