Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 6)
define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_BUILD, 42)
define(_CLIENT_VERSION_BUILD, 43)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true )
define(_COPYRIGHT_YEAR, 2026)
Expand Down
34 changes: 25 additions & 9 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,6 @@ class CMainParams : public CChainParams {
// Two days
consensus.nASERTHalfLife = 2 * 24 * 60 * 60;

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

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

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

// ASERT DAA deployment (uses global defaults for period/threshold)
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = 1772323200LL; // 2026-03-01
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = 1803859200LL; // 2027-03-01
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;

/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
Expand Down Expand Up @@ -242,8 +246,6 @@ class CTestNetParams : public CChainParams {
// One hour
consensus.nASERTHalfLife = 60 * 60;

// ASERT always active on testnet
consensus.asertActivationTime = 0;
consensus.nBitsMin = 32;
consensus.nBitsMax = 1022;

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

// ASERT DAA deployment
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;

//Number of rounds for gHash to generate random Ws around which to search for semiprimes.
consensus.hashRounds = 1;

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

// ASERT always active on signet
consensus.asertActivationTime = 0;
consensus.nBitsMin = 32;
consensus.nBitsMax = 1022;

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

// ASERT DAA deployment
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;

vFixedSeeds.clear();
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
Expand Down Expand Up @@ -497,8 +509,6 @@ class CRegTestParams : public CChainParams {
// One hour (match testnet for fast testing)
consensus.nASERTHalfLife = 60 * 60;

// ASERT always active on regtest
consensus.asertActivationTime = 0;
consensus.nBitsMin = 32;
consensus.nBitsMax = 1022;

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

// ASERT DAA deployment
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].bit = 24;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_ASERT].min_activation_height = 0;

UpdateActivationParametersFromArgs(args);

vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_
enum DeploymentPos : uint16_t {
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_INTERIM_DAA,
DEPLOYMENT_ASERT,
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down Expand Up @@ -120,7 +121,6 @@ struct Params {
bool fPowNoRetargeting;
int64_t nPowTargetSpacing;
int64_t nASERTHalfLife;
int64_t asertActivationTime;
int32_t nBitsMin; // FACTOR ASERT: minimum allowed nBits (easiest difficulty)
int32_t nBitsMax; // FACTOR ASERT: maximum allowed nBits (hardest difficulty)
int64_t nPowTargetTimespan;
Expand Down
4 changes: 4 additions & 0 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
/*.name =*/ "interim_daa",
/*.gbt_force =*/ true,
},
{
/*.name =*/ "asert",
/*.gbt_force =*/ true,
},
};

std::string DeploymentName(Consensus::BuriedDeployment dep)
Expand Down
78 changes: 31 additions & 47 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,63 +46,54 @@ bool IsASERTEnabled(const Consensus::Params &params,
return false;
}

return pindexPrev->GetBlockTime() >= params.asertActivationTime;
return DeploymentActiveAfter(pindexPrev, params, Consensus::DEPLOYMENT_ASERT);
}

/**
* Returns a pointer to the anchor block used for ASERT.
*
* The anchor is the first block whose timestamp >= asertActivationTime.
* Its difficulty was still set by the old DAA, so it serves as the
* reference point from which ASERT computes all subsequent difficulties.
* The anchor is the last block whose difficulty was set by the old DAA,
* serving as the reference point from which ASERT computes all subsequent
* difficulties.
*
* For ALWAYS_ACTIVE deployments (testnet/signet), the anchor is block 1.
* For real BIP9 activation, the anchor is the last block of the LOCKED_IN
* period (one before the first block of the ACTIVE period).
*
* This function is meant to be removed some time after the upgrade, once
* the anchor block is deeply buried, and behind a hard-coded checkpoint.
*
* Preconditions: - pindex must not be nullptr
* - pindex must satisfy: IsASERTEnabled(params, pindex) == true
* Postcondition: Returns a pointer to the first (lowest) block for which
* IsASERTEnabled is true, and for which IsASERTEnabled(pprev)
* is false (or for which pprev is nullptr). The return value may
* be pindex itself.
* Precondition: pindex must not be nullptr.
* Postcondition: Returns a pointer to the anchor block, which is an
* ancestor of (or equal to) pindex.
*/
static const CBlockIndex *GetASERTAnchorBlock(const CBlockIndex *const pindex,
const Consensus::Params &params) {
assert(pindex);

// - We check if we have a cached result, and if we do and it is really the
// ancestor of pindex, then we return it.
//
// - If we do not or if the cached result is not the ancestor of pindex,
// then we proceed with the more expensive walk back to find the ASERT
// anchor block.
//
// CBlockIndex::GetAncestor() is reasonably efficient; it uses CBlockIndex::pskip
// Note that if pindex == cachedAnchor, GetAncestor() here will return cachedAnchor,
// which is what we want.
// Fast path: if we have a cached anchor that is an ancestor of pindex,
// return it immediately (no versionbits query needed).
// Note that if pindex == cachedAnchor, GetAncestor() returns cachedAnchor.
const CBlockIndex *lastCached = cachedAnchor.load();
if (lastCached && pindex->GetAncestor(lastCached->nHeight) == lastCached)
return lastCached;

// Slow path: walk back until we find the first ancestor for which IsASERTEnabled() == true.
const CBlockIndex *anchor = pindex;

while (anchor->pprev) {
// first, skip backwards testing IsASERTEnabled
// The below code leverages CBlockIndex::pskip to walk back efficiently.
if (IsASERTEnabled(params, anchor->pskip)) {
// skip backward
anchor = anchor->pskip;
continue; // continue skipping
}
// cannot skip here, walk back by 1
if (!IsASERTEnabled(params, anchor->pprev)) {
// found it -- highest block where ASERT is not enabled is anchor->pprev, and
// anchor points to the first block for which IsASERTEnabled() == true
break;
}
anchor = anchor->pprev;
}
// StateSinceHeight returns:
// 0 for ALWAYS_ACTIVE (no chain walk)
// H for real BIP9 (first block of the ACTIVE period)
//
// The anchor is the last block computed by the old DAA:
// block 1 for ALWAYS_ACTIVE (genesis has no ASERT history)
// block H-1 for real BIP9 (last block of LOCKED_IN period)
int activeSince = g_versionbitscache.StateSinceHeight(
pindex, params, Consensus::DEPLOYMENT_ASERT);
int anchorHeight = (activeSince <= 1) ? 1 : activeSince - 1;

// GetAncestor(h) returns the block at height h (the block itself when
// h == pindex->nHeight), so when computing difficulty for the first
// ACTIVE block — where pindex is the anchor — this returns pindex.
const CBlockIndex *anchor = pindex->GetAncestor(anchorHeight);
assert(anchor != nullptr);

// Overwrite the cache with the anchor we found. More likely than not, the next
// time we are asked to validate a header it will be part of same / similar chain, not
Expand Down Expand Up @@ -223,14 +214,7 @@ static uint16_t GetNextFACTORASERTWorkRequired(
}

// Anchor selection
const CBlockIndex *pindexAnchor;
if (params.asertActivationTime == 0) {
// Testnet / regtest / signet: anchor is always block 1
pindexAnchor = pindexPrev->GetAncestor(1);
} else {
// Mainnet: first block where block time >= activation time
pindexAnchor = GetASERTAnchorBlock(pindexPrev, params);
}
const CBlockIndex *pindexAnchor = GetASERTAnchorBlock(pindexPrev, params);
assert(pindexAnchor != nullptr);

// Normalize anchor nBits to even (floor) and clamp into [nBitsMin, nBitsMax].
Expand Down
Loading