message: Prevent callback overruns in InvalidateBlock and RewindBlockIndex
diff: @@ -2642,6 +2642,14 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
  }
  }
  +static void LimitValidationInterfaceQueue() {
  + AssertLockNotHeld(cs_main);
  +
  + if (GetMainSignals().CallbacksPending() > 10) {
  + SyncWithValidationInterfaceQueue();
  + }
  +}
  +
  /**
  * Make the best chain active, in multiple steps. The result is either failure
  * or an activated best chain. pblock is either nullptr or a pointer to a block
  @@ -2670,15 +2678,13 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
  do {
  boost::this_thread::interruption_point();
  - if (GetMainSignals().CallbacksPending() > 10) {
  // Block until the validation queue drains. This should largely
  // never happen in normal operation, however may happen during
  // reindex, causing memory blowup if we run too far ahead.
  // Note that if a validationinterface callback ends up calling
  // ActivateBestChain this may lead to a deadlock! We should
  // probably have a DEBUG_LOCKORDER test for this in the future.
  - SyncWithValidationInterfaceQueue();
  - }
  + LimitValidationInterfaceQueue();
  {
  LOCK(cs_main);
  @@ -2796,6 +2802,9 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
  while (true) {
  if (ShutdownRequested()) break;
  + // Make sure the queue of validation callbacks doesn't grow unboundedly.
  + LimitValidationInterfaceQueue();
  +
  LOCK(cs_main);
  if (!chainActive.Contains(pindex)) break;
  pindex_was_in_chain = true;
  @@ -4285,6 +4294,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
  tip = tip->pprev;
  }
  + // Make sure the queue of validation callbacks doesn't grow unboundedly.
  + LimitValidationInterfaceQueue();
  +
  // Occasionally flush state to disk.
  if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) {
  LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
  