Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Sep 7, 2020

The function has several code and logic bugs, which prevent it from working at all:

  • vpindexToConnect.back() is passed to CheckForkWarningConditionsOnNewFork, which is the earliest connected block (least work block), not the new fork tip
  • ActivateBestChainStep will never try to connect a block that descends from an invalid block, so the invalid fork will only ever be of height 1, never hitting the 7 block minimum condition

Instead of dragging the dead and wrong code around through every change in validation, remove it. In the future it could make sense to add a fork detection somewhere outside of the ActivateBestChainStep logic (maybe net_processing).

@maflcko maflcko force-pushed the 2009-noFork branch 2 times, most recently from fabfc65 to fae0f2c Compare September 7, 2020 06:11
@laanwj
Copy link
Member

laanwj commented Sep 8, 2020

Concept ACK on removing complicated warning mechanisms if they don't work at all, and apparently doesn't have any tests either.

@DrahtBot
Copy link
Contributor

DrahtBot commented Sep 19, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

Copy link
Contributor

@dongcarl dongcarl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review ACK fae0f2c

I think you're right on both accounts, and the change looks correct.

I used the following patch on HEAD^ to demonstrate correctness to myself:

diff --git a/src/validation.cpp b/src/validation.cpp
index 58af8744d9..f52d8e87b5 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1340,19 +1340,23 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
 
     // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
     // of our head, drop it
-    if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72)
+    if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72) {
         pindexBestForkTip = nullptr;
+        assert(false);
+    }
 
     if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)))
     {
         if (!GetfLargeWorkForkFound() && pindexBestForkBase)
         {
+            assert(false);
             std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
                 pindexBestForkBase->phashBlock->ToString() + std::string("'");
             AlertNotify(warning);
         }
         if (pindexBestForkTip && pindexBestForkBase)
         {
+            assert(false);
             LogPrintf("%s: 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", __func__,
                    pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(),
                    pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString());
@@ -1397,6 +1401,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) E
             pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
             ::ChainActive().Height() - pindexNewForkTip->nHeight < 72)
     {
+        assert(false);
         pindexBestForkTip = pindexNewForkTip;
         pindexBestForkBase = pfork;
     }
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 501bf7e637..c0a266613c 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -26,6 +26,7 @@ void SetMiscWarning(const bilingual_str& warning)
 void SetfLargeWorkForkFound(bool flag)
 {
     LOCK(g_warnings_mutex);
+    assert(!flag);
     fLargeWorkForkFound = flag;
 }

For the future, I do wonder if it might be better to instead have GetWarnings reach into validation.cpp and perform the comparison between the active tip and pindexBestInvalid when it's needed.

This does 2 things:

  1. validation will no longer depend on warnings.cpp
  2. We will no longer have to reason about when to update fLargeWorkInvalidChainFound

@maflcko
Copy link
Member Author

maflcko commented Oct 27, 2020

The system has been introduced in #2658 , where it was tested to be working. So it might have been working at one point, but might be broken after commit 4e0eed8 (not verified, just a guess). Also the bugfix in commit a2f678d is presumably incomplete.

@maflcko
Copy link
Member Author

maflcko commented Oct 27, 2020

For the future, I do wonder if it might be better to instead have GetWarnings reach into validation.cpp and perform the comparison between the active tip and pindexBestInvalid when it's needed.

Sounds good. To keep the changes here delete-only, I am happy to address the suggestion in a follow-up or volunteer for review if someone beats me to it.

@practicalswift
Copy link
Contributor

Concept ACK

@dongcarl
Copy link
Contributor

re-ACK fae6cef

Copy link
Contributor

@jnewbery jnewbery left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the analysis here that CheckForkWarningConditionsOnNewFork() can only be called with a CBlockIndex which is for a block that is on the valid chain or the child of a block on the valid chain. This code is therefore dead and should be removed.

@jnewbery
Copy link
Contributor

jnewbery commented Nov 3, 2020

utACK fa7eed5

@fjahr
Copy link
Contributor

fjahr commented Nov 4, 2020

Code review ACK fa7eed5

I agree that this code is broken as described and removing and looking for a better approach seems the right way to go.

Copy link
Member

@glozow glozow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK fa7eed5 I see that it's dead code

@maflcko maflcko merged commit a64ff1c into bitcoin:master Nov 18, 2020
@maflcko maflcko deleted the 2009-noFork branch November 18, 2020 10:26
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Nov 18, 2020
fa7eed5 doc: Clarify that vpindexToConnect is in reverse order (MarcoFalke)
fa62304 Remove dead CheckForkWarningConditionsOnNewFork (MarcoFalke)

Pull request description:

  The function has several code and logic bugs, which prevent it from working at all:

  * `vpindexToConnect.back()` is passed to `CheckForkWarningConditionsOnNewFork`, which is the earliest connected block (least work block), *not* the new fork tip
  * `ActivateBestChainStep` will never try to connect a block that descends from an invalid block, so the invalid fork will only ever be of height 1, never hitting the 7 block minimum condition

  Instead of dragging the dead and wrong code around through every change in validation, remove it. In the future it could make sense to add a fork detection somewhere outside of the `ActivateBestChainStep` logic (maybe net_processing).

ACKs for top commit:
  jnewbery:
    utACK fa7eed5
  fjahr:
    Code review ACK fa7eed5
  glozow:
    utACK bitcoin@fa7eed5 I see that it's dead code

Tree-SHA512: 815bdbac7c1eb5b7594b0866a2dbd3c7619797afaadb03a5269fb96739ffb83b05b8e4f7c1e68d48d7886132dd0b12c14c3fb4ee0e72de1074726050ed203e1a
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants