Skip to content

Commit e558d42

Browse files
Merge pull request #54 from NyanCatTW1/202604update
Use BIP9 activation for ASERT
2 parents ce75198 + f632ef0 commit e558d42

7 files changed

Lines changed: 156 additions & 132 deletions

File tree

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
AC_PREREQ([2.69])
22
define(_CLIENT_VERSION_MAJOR, 6)
33
define(_CLIENT_VERSION_MINOR, 0)
4-
define(_CLIENT_VERSION_BUILD, 42)
4+
define(_CLIENT_VERSION_BUILD, 43)
55
define(_CLIENT_VERSION_RC, 0)
66
define(_CLIENT_VERSION_IS_RELEASE, true )
77
define(_COPYRIGHT_YEAR, 2026)

src/chainparams.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ class CMainParams : public CChainParams {
108108
// Two days
109109
consensus.nASERTHalfLife = 2 * 24 * 60 * 60;
110110

111-
// ASERT activation time: 2026-04-20 10:09:00 UTC, at FACT's birthday
112-
consensus.asertActivationTime = 1776679740;
113111
consensus.nBitsMin = 32;
114112
consensus.nBitsMax = 1022;
115113

@@ -119,7 +117,7 @@ class CMainParams : public CChainParams {
119117
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
120118
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
121119
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
122-
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 1; // No activation delay
120+
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
123121

124122
consensus.nMinimumChainWork = uint256S("0x10a8");
125123
consensus.defaultAssumeValid = genesis.GetHash();
@@ -145,6 +143,12 @@ class CMainParams : public CChainParams {
145143
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].nThreshold = Consensus::INTERIM_DAA_THRESHOLD;
146144
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].max_active_blocks = Consensus::INTERIM_DAA_MAX_ACTIVE;
147145

146+
// ASERT DAA deployment (uses global defaults for period/threshold)
147+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
148+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = 1772323200LL; // 2026-03-01
149+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = 1803859200LL; // 2027-03-01
150+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;
151+
148152
/**
149153
* The message start string is designed to be unlikely to occur in normal data.
150154
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -242,8 +246,6 @@ class CTestNetParams : public CChainParams {
242246
// One hour
243247
consensus.nASERTHalfLife = 60 * 60;
244248

245-
// ASERT always active on testnet
246-
consensus.asertActivationTime = 0;
247249
consensus.nBitsMin = 32;
248250
consensus.nBitsMax = 1022;
249251

@@ -275,6 +277,12 @@ class CTestNetParams : public CChainParams {
275277
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].nThreshold = Consensus::INTERIM_DAA_THRESHOLD;
276278
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].max_active_blocks = Consensus::INTERIM_DAA_MAX_ACTIVE;
277279

280+
// ASERT DAA deployment
281+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
282+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
283+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
284+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;
285+
278286
//Number of rounds for gHash to generate random Ws around which to search for semiprimes.
279287
consensus.hashRounds = 1;
280288

@@ -404,8 +412,6 @@ class SigNetParams : public CChainParams {
404412
// Two days
405413
consensus.nASERTHalfLife = 2 * 24 * 60 * 60;
406414

407-
// ASERT always active on signet
408-
consensus.asertActivationTime = 0;
409415
consensus.nBitsMin = 32;
410416
consensus.nBitsMax = 1022;
411417

@@ -448,6 +454,12 @@ class SigNetParams : public CChainParams {
448454
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].nThreshold = Consensus::INTERIM_DAA_THRESHOLD;
449455
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].max_active_blocks = Consensus::INTERIM_DAA_MAX_ACTIVE;
450456

457+
// ASERT DAA deployment
458+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
459+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
460+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
461+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;
462+
451463
vFixedSeeds.clear();
452464
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
453465
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -497,8 +509,6 @@ class CRegTestParams : public CChainParams {
497509
// One hour (match testnet for fast testing)
498510
consensus.nASERTHalfLife = 60 * 60;
499511

500-
// ASERT always active on regtest
501-
consensus.asertActivationTime = 0;
502512
consensus.nBitsMin = 32;
503513
consensus.nBitsMax = 1022;
504514

@@ -542,6 +552,12 @@ class CRegTestParams : public CChainParams {
542552
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].nThreshold = Consensus::INTERIM_DAA_THRESHOLD;
543553
consensus.vDeployments[Consensus::DEPLOYMENT_INTERIM_DAA].max_active_blocks = Consensus::INTERIM_DAA_MAX_ACTIVE;
544554

555+
// ASERT DAA deployment
556+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
557+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = 0;
558+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
559+
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;
560+
545561
UpdateActivationParametersFromArgs(args);
546562

547563
vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.

src/consensus/params.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_
3131
enum DeploymentPos : uint16_t {
3232
DEPLOYMENT_TESTDUMMY,
3333
DEPLOYMENT_INTERIM_DAA,
34+
DEPLOYMENT_ASERT,
3435
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
3536
MAX_VERSION_BITS_DEPLOYMENTS
3637
};
@@ -120,7 +121,6 @@ struct Params {
120121
bool fPowNoRetargeting;
121122
int64_t nPowTargetSpacing;
122123
int64_t nASERTHalfLife;
123-
int64_t asertActivationTime;
124124
int32_t nBitsMin; // FACTOR ASERT: minimum allowed nBits (easiest difficulty)
125125
int32_t nBitsMax; // FACTOR ASERT: maximum allowed nBits (hardest difficulty)
126126
int64_t nPowTargetTimespan;

src/deploymentinfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
1515
/*.name =*/ "interim_daa",
1616
/*.gbt_force =*/ true,
1717
},
18+
{
19+
/*.name =*/ "asert",
20+
/*.gbt_force =*/ true,
21+
},
1822
};
1923

2024
std::string DeploymentName(Consensus::BuriedDeployment dep)

src/pow.cpp

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -46,63 +46,54 @@ bool IsASERTEnabled(const Consensus::Params &params,
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
*/
6970
static const CBlockIndex *GetASERTAnchorBlock(const CBlockIndex *const pindex,
7071
const Consensus::Params &params) {
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

Comments
 (0)