diff --git a/src/chain.cpp b/src/chain.cpp index 4e2d1bf0ac8..3dd22634110 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -5,6 +5,7 @@ #include #include +#include #include std::string CBlockFileInfo::ToString() const @@ -158,18 +159,26 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr /** Find the last common ancestor two blocks have. * Both pa and pb must be non-nullptr. */ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) { + // First rewind to the last common height (the forking point cannot be past one of the two). if (pa->nHeight > pb->nHeight) { pa = pa->GetAncestor(pb->nHeight); } else if (pb->nHeight > pa->nHeight) { pb = pb->GetAncestor(pa->nHeight); } - - while (pa != pb && pa && pb) { + while (pa != pb) { + // Jump back until pa and pb have a common "skip" ancestor. + while (pa->pskip != pb->pskip) { + // This logic relies on the property that equal-height blocks have equal-height skip + // pointers. + Assume(pa->nHeight == pb->nHeight); + Assume(pa->pskip->nHeight == pb->pskip->nHeight); + pa = pa->pskip; + pb = pb->pskip; + } + // At this point, pa and pb are different, but have equal pskip. The forking point lies in + // between pa/pb on the one end, and pa->pskip/pb->pskip on the other end. pa = pa->pprev; pb = pb->pprev; } - - // Eventually all chain branches meet at the genesis block. - assert(pa == pb); return pa; }