Skip to content

Candidate for 6.0.4 release - #2293

Merged
kushti merged 53 commits into
masterfrom
v6.0.4
Aug 18, 2026
Merged

Candidate for 6.0.4 release#2293
kushti merged 53 commits into
masterfrom
v6.0.4

Conversation

This was referenced May 29, 2026
a-shannon and others added 17 commits July 20, 2026 02:56
…-ids

Prevent duplicate IDs in OrderedTxPool
Fix indentation in openapi.yaml for CommitmentWithSecret
Block candidate generation improvements
Preserve extra index consistency across chain switches
PoPowHeader's encoder emits interlinksProof and its decoder requires it, but the PopowHeader schema listed only header and interlinks, so the documented shape did not match the one the node serves. Add the field, and a BatchMerkleProof schema matching what batchMerkleProofEncoder produces.

Noticed while reading #1384.
…ests

Close state storage in the UTXO and digest state property tests
…-proof-openapi

Document interlinksProof in the PopowHeader OpenAPI schema

@jozanek jozanek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full 6.0.4 candidate diff. No protocol/consensus concerns: no serializer or validation-rule changes; the new txIds on LocalBlockApplied/RemoteBlockApplied is internal event-stream only, never on the wire; appVersion/openapi version stamps are consistent.

Findings: 1 MAJOR, 3 MINOR, 2 NIT — inline. The same findings are posted on #2416, which builds on this branch, so fixing them once on v6.0.4 and syncing forward resolves both.

context.become(receive.orElse(loaded(newState)))
self ! Index()
} else {
log.info("Deferring catch-up because the next header does not extend the indexed tip")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR After "Deferring catch-up" no retry is scheduled, and while caughtUp = false the actor has no FullBlockApplied handler — only a Rollback event can resume indexing. If a headers-only fork briefly becomes the best header chain and then loses without the full-block chain ever switching (the losing side of a miner race), no Rollback is published and the indexer stays stalled until restart, dropping all further FullBlockApplied events.

Suggestion: case _: FullBlockApplied if !state.caughtUp && !state.rollbackInProgress => self ! Index(), or re-schedule Index() with a delay instead of only logging.

if (modCount >= saveLimit) saveProgress(newState)
context.become(receive.orElse(loaded(newState)))
self ! Index()
val nextHeaderOpt = history.bestHeaderAtHeight(state.indexedHeight + 1)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR This adds a bestHeaderAtHeight(h + 1) read per block during catch-up, and index() re-reads bestHeaderIdAtHeight(height) at line 381 (headerOpt is None on this path) — two redundant storage reads per block on the reindex hot path. Passing the already-fetched nextHeaderOpt into index() would reuse a single read.

))
})
} ~
(path(".well-known" / "ai-plugin.json") & get) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Removing /openapi.yaml and /.well-known/ai-plugin.json is clearly intentional (ChatGPT-plugin retirement), but it is a breaking removal of public endpoints — anything still fetching them gets a 404 after upgrade. Worth an explicit line in the 6.0.4 release notes.

// `lazy` so the container is only started when a test actually touches `node`.
// The single test below is currently `ignore`d (the openapi-checker image is gone),
// so without `lazy` we would start and tear down a node for nothing.
lazy val node: Node = docker.startDevNetNode(offlineGeneratingPeer).get

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR The spec's only test remains ignored (the openapi-checker image is gone), so this suite passes CI while providing zero signal — the new comment documents the situation but keeps the dead spec. Consider deleting the spec or reviving the check with a maintained validator image.

private val mempoolCapacity = settings.nodeSettings.mempoolCapacity

private def withoutTransaction(id: ModifierId): TreeMap[WeightedTxId, UnconfirmedTransaction] = {
// Keep healthy mutations logarithmic; scan by ID only after cardinality diverges.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT The size-equality heuristic takes the fast path on compensating corruption — one duplicate key plus one orphaned entry leaves the sizes equal, so a duplicate would survive withoutTransaction. Fine as best-effort self-healing, but worth extending the comment to note that limitation.

done.await()
awaitCondition(done)
indexer ! GenerateBetterChainTip()
lock.lock()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT awaitCondition fixes the lock discipline (the old pattern never unlocks after await()), but this test still uses bare lock.lock(); created.await() in two places. Worth finishing the migration to awaitCondition(created) here too.

@kushti
kushti merged commit c313356 into master Aug 18, 2026
15 of 16 checks passed
@kushti
kushti deleted the v6.0.4 branch August 18, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants