Skip to content

Conversation

@HowHsu
Copy link

@HowHsu HowHsu commented Jul 4, 2025

When pindex_prev is the chain tip, return early rather than mixing it
with the reorg case.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 4, 2025

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

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32875.

Reviews

See the guideline for information on the review process.
A summary of reviews will appear here.

Conflicts

No conflicts as of last run.

Copy link
Contributor

@stickies-v stickies-v left a comment

Choose a reason for hiding this comment

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

You're correct that the current docstring is incorrect. I personally don't find your suggestion very clear either, as the two cases talk about different parts of the return statement.

An alternative would be to keep the docstring as-is and just make the chaintip case more explicit in code:

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex || pindex_prev == chain.Tip()) {
        return pindex;
    }
git diff on d6bf3b1cc2
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 8c958ac5f6..506ee73d2e 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -140,15 +140,12 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
     }
 
     const CBlockIndex* pindex = chain.Next(pindex_prev);
-    if (pindex) {
+    if (pindex || pindex_prev == chain.Tip()) {
         return pindex;
     }
 
-    // Two cases goes here:
-    // 1. pindex_prev is the tip: chain.FindFork(pindex_pre) returns pindex_prev itself
-    // 2. pindex_prev is not in m_chain: since block is not in the chain, return the next
-    // block in the chain AFTER the last common ancestor. Caller will be responsible for
-    // rewinding back to the common ancestor.
+    // If block is not in the chain, return the next block in the chain AFTER the last common ancestor.
+    // Caller will be responsible for rewinding back to the common ancestor.
     return chain.Next(chain.FindFork(pindex_prev));
 }
 

@HowHsu
Copy link
Author

HowHsu commented Jul 4, 2025

You're correct that the current docstring is incorrect. I personally don't find your suggestion very clear either, as the two cases talk about different parts of the return statement.

An alternative would be to keep the docstring as-is and just make the chaintip case more explicit in code:

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex || pindex_prev == chain.Tip()) {
        return pindex;
    }

git diff on d6bf3b1

True, I'll update it.

@HowHsu
Copy link
Author

HowHsu commented Jul 4, 2025

You're correct that the current docstring is incorrect. I personally don't find your suggestion very clear either, as the two cases talk about different parts of the return statement.

An alternative would be to keep the docstring as-is and just make the chaintip case more explicit in code:

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex || pindex_prev == chain.Tip()) {
        return pindex;
    }

git diff on d6bf3b1

Hey stickies-v, do you mind me add Suggested-by tag of you?

@luke-jr
Copy link
Member

luke-jr commented Jul 7, 2025

    CBlockIndex* NextInclRewind(const CBlockIndex* pindex) const
    {
        if (!Contains(Assert(pindex))) {
            pindex = Assert(FindFork(pindex));
        }
        return (*this)[pindex->nHeight + 1];
    }

When pindex_prev is the chain tip, return early rather than mixing it
with the reorg case.

Suggested-by: stickies-v
@HowHsu
Copy link
Author

HowHsu commented Sep 18, 2025

    CBlockIndex* NextInclRewind(const CBlockIndex* pindex) const
    {
        if (!Contains(Assert(pindex))) {
            pindex = Assert(FindFork(pindex));
        }
        return (*this)[pindex->nHeight + 1];
    }

Hi Luke,
If I'm not getting you wrong, NextInclRewind() will be a method member of CChain, but from my perspective, this function
seems tailored to a very specific scenario. To keep the class more general and lightweight, it might be better to set this logic as
a separate function just like NextSyncBlock(). And based on that, NextSyncBlock() is already doing well, so how about just tweak if (pindex) to if (pindex || pindex_prev == chain.Tip()) to keep a minimum change?

@HowHsu HowHsu requested review from l0rinc and stickies-v September 18, 2025 10:47
@HowHsu HowHsu changed the title index: Fix missing case in the comment in NextSyncBlock() index: handle case where pindex_prev equals chain tip in NextSyncBlock() Sep 19, 2025

const CBlockIndex* pindex = chain.Next(pindex_prev);
if (pindex) {
if (pindex || pindex_prev == chain.Tip()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks correct, but very hard to read IMHO. In the special case pindex_prev == chain.Tip() the chain.Next() will return nullptr, so in this case pindex will be nullptr.
Moreover, in this case calling next could be avoided.

I'd be happier with this:

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex) {
        return pindex;
    }
    if (pindex_prev == chain.Tip()) {
        return nullptr;
    }

or even better:

    // if at the tip, there is no next
    if (pindex_prev == chain.Tip()) {
        return nullptr;
    }
    if (const CBlockIndex* pindex = chain.Next(pindex_prev); pindex) {
        return pindex;
    }

@optout21
Copy link
Contributor

I see this as a slight optimization -- early exit handling of a special case. Unit tests would be much welcome to this method! Left some comments regarding the implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants