@@ -46,63 +46,54 @@ bool IsASERTEnabled(const Consensus::Params ¶ms,
4646 return false ;
4747 }
4848
49- return pindexPrev-> GetBlockTime () >= params. asertActivationTime ;
49+ return DeploymentActiveAfter (pindexPrev, params, Consensus::DEPLOYMENT_ASERT) ;
5050}
5151
5252/* *
5353 * Returns a pointer to the anchor block used for ASERT.
5454 *
55- * The anchor is the first block whose timestamp >= asertActivationTime.
56- * Its difficulty was still set by the old DAA, so it serves as the
57- * reference point from which ASERT computes all subsequent difficulties.
55+ * The anchor is the last block whose difficulty was set by the old DAA,
56+ * serving as the reference point from which ASERT computes all subsequent
57+ * difficulties.
58+ *
59+ * For ALWAYS_ACTIVE deployments (testnet/signet), the anchor is block 1.
60+ * For real BIP9 activation, the anchor is the last block of the LOCKED_IN
61+ * period (one before the first block of the ACTIVE period).
5862 *
5963 * This function is meant to be removed some time after the upgrade, once
6064 * the anchor block is deeply buried, and behind a hard-coded checkpoint.
6165 *
62- * Preconditions: - pindex must not be nullptr
63- * - pindex must satisfy: IsASERTEnabled(params, pindex) == true
64- * Postcondition: Returns a pointer to the first (lowest) block for which
65- * IsASERTEnabled is true, and for which IsASERTEnabled(pprev)
66- * is false (or for which pprev is nullptr). The return value may
67- * be pindex itself.
66+ * Precondition: pindex must not be nullptr.
67+ * Postcondition: Returns a pointer to the anchor block, which is an
68+ * ancestor of (or equal to) pindex.
6869 */
6970static const CBlockIndex *GetASERTAnchorBlock (const CBlockIndex *const pindex,
7071 const Consensus::Params ¶ms) {
7172 assert (pindex);
7273
73- // - We check if we have a cached result, and if we do and it is really the
74- // ancestor of pindex, then we return it.
75- //
76- // - If we do not or if the cached result is not the ancestor of pindex,
77- // then we proceed with the more expensive walk back to find the ASERT
78- // anchor block.
79- //
80- // CBlockIndex::GetAncestor() is reasonably efficient; it uses CBlockIndex::pskip
81- // Note that if pindex == cachedAnchor, GetAncestor() here will return cachedAnchor,
82- // which is what we want.
74+ // Fast path: if we have a cached anchor that is an ancestor of pindex,
75+ // return it immediately (no versionbits query needed).
76+ // Note that if pindex == cachedAnchor, GetAncestor() returns cachedAnchor.
8377 const CBlockIndex *lastCached = cachedAnchor.load ();
8478 if (lastCached && pindex->GetAncestor (lastCached->nHeight ) == lastCached)
8579 return lastCached;
8680
87- // Slow path: walk back until we find the first ancestor for which IsASERTEnabled() == true.
88- const CBlockIndex *anchor = pindex;
89-
90- while (anchor->pprev ) {
91- // first, skip backwards testing IsASERTEnabled
92- // The below code leverages CBlockIndex::pskip to walk back efficiently.
93- if (IsASERTEnabled (params, anchor->pskip )) {
94- // skip backward
95- anchor = anchor->pskip ;
96- continue ; // continue skipping
97- }
98- // cannot skip here, walk back by 1
99- if (!IsASERTEnabled (params, anchor->pprev )) {
100- // found it -- highest block where ASERT is not enabled is anchor->pprev, and
101- // anchor points to the first block for which IsASERTEnabled() == true
102- break ;
103- }
104- anchor = anchor->pprev ;
105- }
81+ // StateSinceHeight returns:
82+ // 0 for ALWAYS_ACTIVE (no chain walk)
83+ // H for real BIP9 (first block of the ACTIVE period)
84+ //
85+ // The anchor is the last block computed by the old DAA:
86+ // block 1 for ALWAYS_ACTIVE (genesis has no ASERT history)
87+ // block H-1 for real BIP9 (last block of LOCKED_IN period)
88+ int activeSince = g_versionbitscache.StateSinceHeight (
89+ pindex, params, Consensus::DEPLOYMENT_ASERT);
90+ int anchorHeight = (activeSince <= 1 ) ? 1 : activeSince - 1 ;
91+
92+ // GetAncestor(h) returns the block at height h (the block itself when
93+ // h == pindex->nHeight), so when computing difficulty for the first
94+ // ACTIVE block — where pindex is the anchor — this returns pindex.
95+ const CBlockIndex *anchor = pindex->GetAncestor (anchorHeight);
96+ assert (anchor != nullptr );
10697
10798 // Overwrite the cache with the anchor we found. More likely than not, the next
10899 // time we are asked to validate a header it will be part of same / similar chain, not
@@ -223,14 +214,7 @@ static uint16_t GetNextFACTORASERTWorkRequired(
223214 }
224215
225216 // Anchor selection
226- const CBlockIndex *pindexAnchor;
227- if (params.asertActivationTime == 0 ) {
228- // Testnet / regtest / signet: anchor is always block 1
229- pindexAnchor = pindexPrev->GetAncestor (1 );
230- } else {
231- // Mainnet: first block where block time >= activation time
232- pindexAnchor = GetASERTAnchorBlock (pindexPrev, params);
233- }
217+ const CBlockIndex *pindexAnchor = GetASERTAnchorBlock (pindexPrev, params);
234218 assert (pindexAnchor != nullptr );
235219
236220 // Normalize anchor nBits to even (floor) and clamp into [nBitsMin, nBitsMax].
0 commit comments