Repository navigation
fix(core): accept SLA rollups with no reports - #596
Merged
Merged
Conversation
isValidRollup compared the locally built reports with the proposed ones using reflect.DeepEqual. createRollup builds an empty non-nil slice, but the proposed rollup has been through proto unmarshalling, which decodes an empty repeated field as nil, and DeepEqual treats nil and empty as different. With no registered validators every rollup therefore failed validation on every node, its proposer included, and the chain could not advance past the first rollup height. This never happened on audius-mainnet-alpha-beta because it always had registered validators. A chain bootstrapped from genesis-writer output starts with an empty core_validators table and is due a rollup at its first live block, so the bootstrap node rejects its own proposal forever. Move the comparison into rollupsMatch and treat empty-on-both-sides as a match. Non-empty reports keep the original DeepEqual comparison, so existing chains validate exactly as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
isValidRollupcompares the reports this node builds with the ones in the proposed rollup usingreflect.DeepEqual.createRollupalways builds an empty non-nil slice, but the proposed rollup has been through proto unmarshalling, which decodes an empty repeated field as nil.DeepEqualtreats those as different.So when there are no registered validators, the rollup has no reports and fails validation on every node, including the proposer.
ProcessProposalrejects it, each round re-proposes the same rollup, and the chain cannot get past the first rollup height.This never happened on
audius-mainnet-alpha-betabecause it has always had registered validators. A chain bootstrapped from genesis-writer output starts with an emptycore_validatorstable (the bootstrap validator is in the CometBFT genesis, not in core's registry) and is due its first rollup at its first live block, since the writer's blocks exceedSlaRollupInterval. Booting the 2026-08-25 artifact stalls at height 5840 withInvalid block: invalid rollupandPrevote step: state machine rejected a proposed blockevery round.Fix
Move the comparison into a pure
rollupsMatchfunction and treat "no reports on either side" as a match. Non-empty reports keep the originalreflect.DeepEqualcomparison, so existing chains validate exactly as before.The empty state is transient on a new chain: with zero registered nodes, registration needs
min(0, AttRegistrationMin) = 0attestations, so the bootstrap node registers itself once blocks are moving, and later rollups carry reports.Consensus impact
This changes block validation, but only for a case no existing chain can reach.
audius-mainnet-alpha-betaalways has registered validators, so it always takes the unchangedDeepEqualpath. Onaudius-mainnet-betano block above the genesis artifact has been committed yet, and every node that syncs it will run a binary with this fix.Tests
TestRollupsMatchruns each proposed rollup through a realSignedTransactionmarshal/unmarshal round trip, the path a proposal takes betweenPrepareProposalandProcessProposal. It covers: empty reports (including asserting that decoding yields nil), matching reports, different reports, reports on only one side in both directions, and an off-by-one block range or timestamp.🤖 Generated with Claude Code