v9.26.5: fix DigiDollar oracle startup hang + bury Taproot/DigiDollar/AlgoLock deployments#429
Merged
Merged
Conversation
…bits cache)
WHAT HAPPENED
On startup the node rebuilds its in-memory oracle price + volatility cache by
scanning the last 172,800 blocks (~30 days). For every block it re-evaluated the
BIP9 DigiDollar-activation gate through
IsDigiDollarEnabled(pprev, const Consensus::Params&), which allocates a THROWAWAY
VersionBitsCache and recomputes the deployment's threshold-state machine from
scratch (an O(nPeriod) walk) on each call. With nothing memoized across ~172,800
iterations this took ~15 minutes, run synchronously under LOCK(cs_main) BEFORE
SetRPCWarmupFinished() -- so RPC returned -28 and P2P stalled the whole time, and
the GUI sat on the stale "Verifying blocks..." label. It also emitted 150k+
per-block "Skipping pre-activation" log lines.
THE FIX (one safe change)
The startup per-block gate now evaluates the IDENTICAL BIP9 predicate through the
shared, memoized versionbits cache via a new
ShouldLoadStartupOraclePriceForBlock(int, const CBlockIndex*, const ChainstateManager&)
overload (-> IsDigiDollarEnabled(pprev, chainman)) -- O(1) amortized, exactly the
lookup ConnectBlock already uses. Per-block skip logging is replaced by a single
aggregate count.
This is a PURE performance change: byte-identical to v9.26.4 (no consensus rule
changes). New unit tests prove the two IsDigiDollarEnabled overloads and the
startup gate compute the same activation boolean at every height on a real chain.
Verified live on mainnet: the oracle startup scan dropped from ~15 min to ~3 s
(163,850 pre-activation blocks skipped, one aggregate log line instead of 150k),
and the node came up healthy and caught up.
DELIBERATELY NOT SHIPPED: the durable on-disk price snapshot ("L3"). As designed
it persisted the live-throttled volatility deque and would diverge from a
-reindex node once the rolling 30-day window slides past the activation height
(~28 days out), splitting the chain via the consensus freeze gate. That
underlying anchor-dependence of the freeze-brake throttle is a PRE-EXISTING
v9.26.4 issue; the durable instant-startup optimization and the root throttle fix
are separate, deliberate follow-ups and are not required for this startup-speed
fix.
TESTS
- src/test/digidollar_oracle_startup_tests.cpp: the two IsDigiDollarEnabled
overloads agree, and the startup gate == the BIP9 ConnectBlock predicate, at
every height on a real connected chain.
- test/functional/digidollar_oracle_startup_consensus.py: restart == -reindex ==
pre-restart reconstructed oracle state (consensus-neutral), and no durable
snapshot file is written.
All three BIP9 deployments have completed their lifecycle and are ACTIVE
on mainnet, so this converts them to buried deployments with hardcoded
per-network activation heights — the same housekeeping DigiByte/Bitcoin
already performed for CSV/SegWit/ReserveAlgo/Odo:
mainnet testnet26 signet/regtest
Taproot 21,168,000 0 0
DigiDollar 23,869,440 600 0
AlgoLock 23,869,440 0 0
The heights are the empirically verified BIP9 'since' values: read from
live mainnet getdeploymentinfo (tip 23,882,878) and confirmed block-by-
block on a fully-synced testnet26 node (bit-23 signaling in 200-599,
ACTIVE at exactly 600).
WHY
- The BIP9 state machine serves no further purpose for these
deployments: they can never re-signal, time out, or fail.
- Burying removes every remaining BIP9 threshold-state walk from the
hot paths. ConnectBlock previously evaluated the DigiDollar gate via
the throwaway-VersionBitsCache IsDigiDollarEnabled overload at three
call sites (dd_bip9_active, CheckMuSig2OracleBundleVersion,
ValidateBlockOracleData) at ~5 ms each per DD-era block; all of that
— and the startup-scan cost class fixed by 3ec927b — collapses to
a single O(1) height comparison.
- Blocks stop signaling bits 2/23/0, so GBT version fields are clean
for SHA256D pool stacks (structurally resolves the bit-23
version-rolling interference some pools reported).
CONSENSUS COMPATIBILITY
A v9.26.5 node accepts/rejects exactly the same blocks as v9.26.4 for
every block on the current mainnet and testnet chains. Deliberately
unchanged: the static DD gates (nDDActivationHeight =
nOracleActivationHeight = nDigiDollarMuSig2Height = 23,627,520 mainnet /
600 testnet / 650-650-0 regtest) keep their historical floor role for
prune locks, oracle P2P gating and the pre-floor collateral gate;
EarliestActivationFloor(params) = min(nDDActivationHeight,
DeploymentHeight(DIGIDOLLAR)) is value-preserving on every network; the
AlgoLock nGroestlDeactivationHeight=23,808,000 static backstop remains
OR'd with the deployment check; Taproot script flags were already set
unconditionally so its burial has zero script-consensus effect.
MinBIP9WarningHeight rises to 23,909,760 (mainnet) / 800 (testnet) so
the historical signaling periods do not trigger "unknown new rules"
warnings. Standard BIP90 caveat: only a reorg below the burial heights
onto a differently-signaled chain could be judged differently — no real
chain is affected.
INTERFACE CHANGES (see doc/release-notes/release-notes-9.26.5.md)
- getdeploymentinfo/getblockchaininfo: the three entries become
{"type":"buried","active":...,"height":...} with no bip9 sub-object.
- getdigidollardeploymentinfo: new buried shape (enabled, type, status
active|defined, activation_height = exact burial height); BIP9
signaling fields removed. This also fixes the old back-scan's
off-by-one activation_height report.
- getblocktemplate: rules always lists taproot/digidollar/algolock once
active (hardcoded like "csv"); vbavailable drops them; version never
sets bits 2/23/0.
- Regtest: -digidollaractivationheight=N now activates DigiDollar at
exactly N (buried height + static gates; previously first 144-block
boundary >= max(432, N)); new -testactivationheight=taproot@H/
digidollar@H/algolock@H moves only the buried height;
-vbparams=taproot/digidollar/algolock is now a startup error.
TESTS
- New src/test/deployment_burial_tests.cpp pins the per-network burial
heights, window alignment, floor preservation, knob semantics and the
exact activation boundary.
- Unit/functional suites migrated off BIP9 signaling: state-machine/
threshold/timeout cases that are unrepresentable post-burial were
removed (generic BIP9 remains covered via TESTDUMMY in
versionbits_tests.cpp); everything else was converted to
buried-boundary equivalents preserving intent, including the wave12
constraint that startup oracle-price reconstruction follows the same
activation predicate as block connection.
- Full unit suite: 3,413 test cases, no errors. Full functional
test_runner.py suite: all passed. Verified live on regtest:
buried rendering, knob=432 exact activation, testactivationheight
split semantics, and -vbparams rejection.
Docs updated (CLAUDE.md, DIGIDOLLAR_ACTIVATION_EXPLAINER.md marked
historical + burial section, ARCHITECTURE/REPO_MAP surgical fixes) and
release notes added for v9.26.5.
…ion tests Follow-ups from the 3-agent adversarial review of 09bcb46 (no code defects found; all findings were documentation accuracy or test polish): - Correct the -testactivationheight=digidollar@H claim in the help text, the kernel/chainparams.cpp switch comment, CLAUDE.md, and the release notes: the static DD/oracle gates keep their defaults, but nDigiDollarMuSig2Height is DERIVED as min(nDDActivationHeight, DigiDollarHeight) and so follows H below 650 (verified live: digidollar@300 reports musig2_format_activation_height=300). - Release notes: drop the getblockchaininfo mention — that RPC carries no deployment information in this v26-lineage codebase; only getdeploymentinfo (and REST /deploymentinfo) render the buried entries. - init.cpp: replace the stale "-digidollaractivationheight ... overrides BIP9 activation" help text with the buried exact-height semantics. - rpc_blockchain.py: pin the documented startup-error contracts in CI — -vbparams=digidollar/taproot/algolock now assert "Invalid deployment", and an out-of-range -digidollaractivationheight asserts its error (previously these were only smoke-tested manually).
Plain-language v9.26.5 release notes in the root-directory style of RELEASE_v9.26.2.md / RELEASE_v9.26.3.md: first post-activation release context (DigiDollar live at 23,869,440), the oracle startup-hang fix, the BIP90 burial of Taproot/DigiDollar/AlgoLock with the verified heights, breaking RPC/GBT/regtest interface changes, upgrade guidance, and testing coverage.
|
Please check Gitter and github issues. There are still some other important bugs that should be fixed in v9.26.5. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v9.26.5 — the first post-activation maintenance release. DigiDollar and AlgoLock activated on mainnet at block 23,869,440 (17 July 2026). This PR ships two changes plus their tests and docs:
Fix the ~15-minute DigiDollar oracle startup hang (
3ec927b8b4). The startup oracle-price scan re-ran the BIP9 threshold state machine from scratch through a throwawayVersionBitsCacheon each of ~172,800 per-block gate checks, undercs_main, before RPC warmup — so mainnet nodes sat at RPC -28 / "Verifying blocks…" for ~15 minutes. The gate now uses the shared, memoized versionbits cache (the identical predicate ConnectBlock uses). Verified live on mainnet: ~15 min → ~3 s. Pure performance change; consensus-neutral, pinned by new unit + functional tests (restart ==-reindex== pre-restart oracle state).Bury the Taproot, DigiDollar, and AlgoLock deployments (BIP90) (
09bcb46aab). All three completed their BIP9 lifecycle and are ACTIVE on mainnet, so they become buried deployments with hardcoded per-network heights — the same housekeeping done previously for CSV/SegWit/ReserveAlgo/Odo:Heights are the empirically verified BIP9
sincevalues — read from live mainnetgetdeploymentinfoand verified block-by-block on a fully synced testnet26 node (signaling 200–599, ACTIVE at exactly 600). Burying also removes the last per-block BIP9 recomputation from ConnectBlock (three throwaway-cache call sites, ~15 ms per DD-era block during sync) — every activation check is now one height comparison.Consensus compatibility
A v9.26.5 node accepts/rejects exactly the same blocks as v9.26.4 for every block on the current mainnet and testnet chains. Deliberately unchanged: the static DD gates keep their historical floors (
nDDActivationHeight = nOracleActivationHeight = nDigiDollarMuSig2Height = 23,627,520mainnet / 600 testnet — the prune floor and oracle-P2P gates are untouched, so existing pruned nodes are unaffected); the AlgoLocknGroestlDeactivationHeight = 23,808,000static backstop remains OR'd in; Taproot script flags were already unconditional, so its burial has zero script-consensus effect.MinBIP9WarningHeightrises to 23,909,760 / 800 so historical bit-2/23/0 signaling doesn't trigger "unknown new rules" warnings. Standard BIP90 caveat (deep-reorg hypothetical) applies as it did for Bitcoin's burials; no real chain is affected.Breaking interface changes (details in
doc/release-notes/release-notes-9.26.5.md)getdigidollardeploymentinfo: new buried shape (enabled,type:"buried",status:"active"|"defined",activation_height); BIP9 signaling fields removed; also fixes the old back-scan's off-by-oneactivation_height.getdeploymentinfo/ REST/deploymentinfo: the three entries become{"type":"buried","active":…,"height":…}with nobip9sub-object.getblocktemplate:rulesalways liststaproot/digidollar/algolockonce active (likecsv);versionnever sets bits 2/23/0.-digidollaractivationheight=Nnow activates at exactly N; new-testactivationheight=taproot|digidollar|algolock@H;-vbparamsfor the three buried names is a startup error (CI-pinned).Testing
deployment_burial_testssuite (per-network height pins, window alignment, floor preservation, knob semantics, exact activation boundary).test_runner.pysuite: all pass. DigiDollar activation tests rewritten from BIP9 signaling ladders to buried-boundary lifecycles (pre-activation rejection incl.digidollar-not-activemempool reason, exact boundary flip, post-activation mint/send/redeem, reorg-below-activation purge, multinode/IBD/reindex parity, pruning). Unrepresentable BIP9 scenarios (timeout/FAILED, threshold math, signaling ladders) removed; generic BIP9 coverage remains via TESTDUMMY inversionbits_tests.cpp.-testactivationheightsplit semantics,-vbparamsrejection.5cb7377769).Commits
3ec927b8b4fix: eliminate ~15-min DigiDollar oracle startup hang (shared versionbits cache)d26a3d2469v9.26.5 (version bump)09bcb46aabconsensus: bury Taproot, DigiDollar, and AlgoLock deployments (BIP90)5cb7377769review: fix burial docs/help accuracy, add interface-contract regression tests05b50e229ddoc: add RELEASE_v9.26.5.md root release notesReview guide
Start with
src/consensus/params.h(enum moves +DeploymentHeight), thensrc/kernel/chainparams.cpp(per-network heights, regtest option plumbing), then the five call-site rewrites (consensus/digidollar.cpp,init.cpp,oracle/bundle_manager.cpp,rpc/digidollar.cpp,qt/digidollartab.cpp). Everything else reaches the buried predicates automatically via the existingDeploymentActiveAfter/DeploymentActiveAtoverloads.RELEASE_v9.26.5.md(root) has the plain-language summary.