fix(x/audit): bridge cascade_kademlia_db_bytes from HostReport to SupernodeMetricsState#140
Merged
mateeullahmalik merged 2 commits intoMay 12, 2026
Conversation
…ernodeMetricsState LEP-6 §12 (PR #122) removed cascade_kademlia_db_bytes from the audit HostReport and rewrote x/supernode getLatestCascadeBytesFromAudit to read from SupernodeMetricsState. The migration was half-completed: no chain-side writer was added to populate SupernodeMetricsState.CascadeKademliaDbBytes from the audit epoch-report channel. The only remaining writer is the now-operationally-dead legacy MsgReportSupernodeMetrics handler. Result on chain 1.12.0 / master today: every Everlight payout-period distribution sees getLatestCascadeBytesFromAudit return found=false for every SuperNode → distributePool skips every candidate → pool is never disbursed. Confirmed live on devnet. This change: 1. Restores HostReport.cascade_kademlia_db_bytes (field 6) on the audit epoch-report proto purely as a metric-courier. The audit module does NOT consume the value for its own consensus logic (LEP-6 §12 intent preserved); it only carries the value into the chain on the audit submission channel that SuperNodes already use. 2. Adds validation in SubmitEpochReport: cascade_kademlia_db_bytes must be a finite number ≥ 0 (NaN, +Inf, -Inf, negative rejected with new ErrInvalidHostMetric). Zero is valid (empty Kademlia store). 3. Adds bridgeCascadeBytesToSupernodeMetrics: after the epoch report is successfully persisted, the audit handler upserts the reporter's SupernodeMetricsState via supernodeKeeper.SetMetricsState — read- modify-write so any non-cascade fields previously persisted are preserved. Bumps Height to current block and ReportCount. 4. Defensive no-op (with audit_cascade_bytes_bridge_skipped event for observability) when the SuperNode record has empty/invalid ValidatorAddress — that is a pre-existing x/supernode invariant violation outside audit's scope; the bridge surfaces it via event but does not fail the epoch report on someone else's data corruption. This is now the SOLE writer of SupernodeMetricsState.CascadeKademliaDbBytes post-LEP-6 §12 (legacy MsgReportSupernodeMetrics handler remains in the codec but no SN sends it; left for a follow-up cleanup PR). Tests: - 4 unit tests covering invariant violations (NaN, +Inf, -Inf, negative) - 1 happy-path test (value bridged into MetricsState with correct validator address, height, ReportCount) - 1 zero-valid test - 1 read-modify-write preservation test (non-cascade fields preserved) - 1 defensive no-op test (empty ValidatorAddress emits event, accepts report, does not call Get/SetMetricsState) - Existing 2 storagefull-transition tests updated with Get/SetMetricsState AnyTimes expectations. make integration-tests passes (incl. tests/integration/everlight, tests/integration/audit, tests/integration/supernode). go vet -tags system_test ./... clean in tests/systemtests/.
After the audit→supernode metrics bridge added in this PR, the SupernodeMetricsState is written on every accepted epoch report. The sn-eligibility query now reaches the threshold gate (rawBytes=0) and returns 'cascade bytes below minimum threshold' instead of the pre-bridge 'no audit epoch report found' (which was a symptom of no writer existing). Substantive outcome — SN ineligible, no payout while storage-full — is unchanged. Only the rejection reason advances by one step. Fixes: failing system test TestEverlightSystem_PayoutAndHistoryWhileStorageFull on PR #140 CI.
mateeullahmalik
added a commit
that referenced
this pull request
May 12, 2026
After the audit→supernode metrics bridge added in this PR, the SupernodeMetricsState is written on every accepted epoch report. The sn-eligibility query now reaches the threshold gate (rawBytes=0) and returns 'cascade bytes below minimum threshold' instead of the pre-bridge 'no audit epoch report found' (which was a symptom of no writer existing). Substantive outcome — SN ineligible, no payout while storage-full — is unchanged. Only the rejection reason advances by one step. Fixes: failing system test TestEverlightSystem_PayoutAndHistoryWhileStorageFull on PR #140 CI.
j-rafique
approved these changes
May 12, 2026
mateeullahmalik
added a commit
that referenced
this pull request
May 12, 2026
…tes from HostReport to SupernodeMetricsState (#141) * fix(x/audit): bridge cascade_kademlia_db_bytes from HostReport to SupernodeMetricsState LEP-6 §12 (PR #122) removed cascade_kademlia_db_bytes from the audit HostReport and rewrote x/supernode getLatestCascadeBytesFromAudit to read from SupernodeMetricsState. The migration was half-completed: no chain-side writer was added to populate SupernodeMetricsState.CascadeKademliaDbBytes from the audit epoch-report channel. The only remaining writer is the now-operationally-dead legacy MsgReportSupernodeMetrics handler. Result on chain 1.12.0 / master today: every Everlight payout-period distribution sees getLatestCascadeBytesFromAudit return found=false for every SuperNode → distributePool skips every candidate → pool is never disbursed. Confirmed live on devnet. This change: 1. Restores HostReport.cascade_kademlia_db_bytes (field 6) on the audit epoch-report proto purely as a metric-courier. The audit module does NOT consume the value for its own consensus logic (LEP-6 §12 intent preserved); it only carries the value into the chain on the audit submission channel that SuperNodes already use. 2. Adds validation in SubmitEpochReport: cascade_kademlia_db_bytes must be a finite number ≥ 0 (NaN, +Inf, -Inf, negative rejected with new ErrInvalidHostMetric). Zero is valid (empty Kademlia store). 3. Adds bridgeCascadeBytesToSupernodeMetrics: after the epoch report is successfully persisted, the audit handler upserts the reporter's SupernodeMetricsState via supernodeKeeper.SetMetricsState — read- modify-write so any non-cascade fields previously persisted are preserved. Bumps Height to current block and ReportCount. 4. Defensive no-op (with audit_cascade_bytes_bridge_skipped event for observability) when the SuperNode record has empty/invalid ValidatorAddress — that is a pre-existing x/supernode invariant violation outside audit's scope; the bridge surfaces it via event but does not fail the epoch report on someone else's data corruption. This is now the SOLE writer of SupernodeMetricsState.CascadeKademliaDbBytes post-LEP-6 §12 (legacy MsgReportSupernodeMetrics handler remains in the codec but no SN sends it; left for a follow-up cleanup PR). Tests: - 4 unit tests covering invariant violations (NaN, +Inf, -Inf, negative) - 1 happy-path test (value bridged into MetricsState with correct validator address, height, ReportCount) - 1 zero-valid test - 1 read-modify-write preservation test (non-cascade fields preserved) - 1 defensive no-op test (empty ValidatorAddress emits event, accepts report, does not call Get/SetMetricsState) - Existing 2 storagefull-transition tests updated with Get/SetMetricsState AnyTimes expectations. make integration-tests passes (incl. tests/integration/everlight, tests/integration/audit, tests/integration/supernode). go vet -tags system_test ./... clean in tests/systemtests/. * test(systemtests): update Everlight storage-full eligibility reason After the audit→supernode metrics bridge added in this PR, the SupernodeMetricsState is written on every accepted epoch report. The sn-eligibility query now reaches the threshold gate (rawBytes=0) and returns 'cascade bytes below minimum threshold' instead of the pre-bridge 'no audit epoch report found' (which was a symptom of no writer existing). Substantive outcome — SN ineligible, no payout while storage-full — is unchanged. Only the rejection reason advances by one step. Fixes: failing system test TestEverlightSystem_PayoutAndHistoryWhileStorageFull on PR #140 CI.
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
Bridges
cascade_kademlia_db_bytesfrom the auditHostReport(per-epoch) intox/supernodeSupernodeMetricsState, which is the sole source Everlight payout and eligibility queries read from post LEP-6 §12.Without this fix, Everlight distributes zero ulume to anyone on
masterand1.12.0today — confirmed live on devnet. See "Why this is needed" below.Why this is needed
LEP-6 §12 (PR #122, 2026-04-28):
cascade_kademlia_db_bytes(field 6) fromaudit.HostReportx/supernode/v1/keeper/audit_metrics.go::getLatestCascadeBytesFromAuditto read fromSupernodeMetricsStateinstead of from audit epoch reportsBut the migration was half-completed: no chain-side writer was added to populate
SupernodeMetricsState.CascadeKademliaDbBytesfrom the audit-submission path. The only remaining writer is the now-operationally-dead legacyMsgReportSupernodeMetricshandler — andsupernode@master/v2.5.0-rchas explicitly disabled the legacy reporter (supernode/cmd/start.go:29: "Legacy supernode metrics reporter has been superseded by epoch-scoped audit reporting in x/audit").Result on chain
1.12.0/mastertoday:cascade_kademlia_db_bytesanywheredistributePooliterates all ACTIVE/STORAGE_FULL SNs, callsgetLatestCascadeBytesFromAudit→ returnsfound=falsefor every SNcandidatesslice is empty → no SN receives any payoutQuerySNEligibilityreturnsEligible: false, Reason: "audit report is stale"for every SNThis PR closes the gap by making the audit
SubmitEpochReporthandler the single, sole writer ofSupernodeMetricsState.CascadeKademliaDbBytes, in line with the post-LEP-6 design intent ("only audit-module epoch reports are valid").Behavior change
audit.HostReporthas nocascade_kademlia_db_bytesfieldaudit.HostReport.cascade_kademlia_db_bytes(field 6,double) restored as a metric-couriercascade_kademlia_db_bytesSupernodeMetricsState.CascadeKademliaDbBytesonly written by legacyMsgReportSupernodeMetrics(now dead)SubmitEpochReporthandler after a successful epoch report is persistedInvariant table
HostReport.cascade_kademlia_db_bytesvalidateHostMetricFieldsinmsg_submit_epoch_report.goSubmitEpochReportis the SOLE writer ofSupernodeMetricsState.CascadeKademliaDbBytespost-LEP-6 §12bridgeCascadeBytesToSupernodeMetricsSupernodeMetrics.*fieldsgetLatestCascadeBytesFromAudit,distribution.go,query_get_reward_eligibility.go) unchangedBridge defensively no-ops with an
audit_cascade_bytes_bridge_skippedevent if the SuperNode record has an empty/invalidValidatorAddress(a pre-existingx/supernodeinvariant violation outside audit's scope).Files
proto/lumera/audit/v1/audit.protocascade_kademlia_db_bytes = 6with metric-courier commentx/audit/v1/types/audit.pb.gox/audit/v1/types/errors.goErrInvalidHostMetric(code 18)x/audit/v1/keeper/msg_submit_epoch_report.goSetReportx/audit/v1/keeper/msg_submit_epoch_report_cascade_bytes_test.gox/audit/v1/keeper/msg_submit_epoch_report_storagefull_test.goGetMetricsState/SetMetricsStateAnyTimes()expectations for the 2 storagefull-transition tests whose SN has a real validator addressdocs/static/openapi.ymlRisk & rollback
Risk: low.
Rollback: revert this commit. Devnet/mainnet falls back to the current broken-Everlight state (no worse than today).
Migration / upgrade impact
SupernodeMetricsStateschema unchanged. New writers just start populatingMetrics.CascadeKademliaDbBytesfrom the audit path going forward.supernode@v2.5.0-rc(or anything master-ish on the supernode side that emitsHostReport.cascade_kademlia_db_bytes). Without this PR, those SN binaries' epoch-report Txs fail at proto decode (errUnknownField "*types.HostReport": {TagNum: 6, WireType:"fixed64"}: tx parse error).Verification
Observability
Two new event types:
audit_cascade_bytes_bridge_skipped— emitted when the bridge no-ops due to empty/invalidValidatorAddress. Attributes:module,supernode_account,validator_address(when present),reason,error(when present).Follow-up
The legacy
MsgReportSupernodeMetricshandler remains in the codec (still registered, still callable) but no SN binary sends it. Removing it cleanly requires a chain upgrade handler and is out of scope for this surgical fix — to be done as a follow-up cleanup PR.Cherry-pick plan
After merge to
master, cherry-pick onto1.12.0release branch via a follow-up PR.