Skip to content

[1.12.0] cherry-pick #140: fix(x/audit) bridge cascade_kademlia_db_bytes from HostReport to SupernodeMetricsState#141

Merged
mateeullahmalik merged 2 commits into
1.12.0from
cherry-pick/cascade-bytes-bridge-to-1.12.0
May 12, 2026
Merged

[1.12.0] cherry-pick #140: fix(x/audit) bridge cascade_kademlia_db_bytes from HostReport to SupernodeMetricsState#141
mateeullahmalik merged 2 commits into
1.12.0from
cherry-pick/cascade-bytes-bridge-to-1.12.0

Conversation

@mateeullahmalik
Copy link
Copy Markdown
Contributor

Summary

Cherry-pick of #140 (2c5ee772) onto the 1.12.0 release branch.

PR #140 (merged to master) restores the cascade_kademlia_db_bytes bridge from HostReport (audit module) → SupernodeMetricsState (supernode module). Without this bridge, Everlight reward distribution reads zero cascade-bytes and pays out zero to all SNs.

Behavior change

  • HostReport proto regains field 6 (cascade_kademlia_db_bytes, double) as a metric-courier. The audit module does not consume this field for any audit decision — preserving LEP-6 §12 intent. It is bridged through SubmitEpochReport into SupernodeMetricsState.CascadeKademliaDbBytes, where getLatestCascadeBytesFromAudit (Everlight) reads it.
  • Audit SubmitEpochReport becomes the single writer of SupernodeMetricsState.CascadeKademliaDbBytes. The disabled legacy MsgReportSupernodeMetrics handler is no longer the silent zero-source.
  • Validation enforces non-negative, finite values; non-conforming reports rejected with a typed error.

Rationale

After LEP-6 consolidation (#117, #122), getLatestCascadeBytesFromAudit was repointed at SupernodeMetricsState, but no writer was wired up post-disable of MsgReportSupernodeMetrics. Result: Everlight payout = 0 for every SN, every period. Devnet validation confirmed this end-to-end.

Risks

  • Determinism: Single-writer property + per-path validation tests added. No wall-clock or non-deterministic input.
  • Replay safety: Field 6 is proto-optional with explicit zero handling; old reports decode correctly.
  • Upgrade compatibility: This change introduces a new proto field on HostReport. Mainnet rollout MUST go via a coordinated MsgSoftwareUpgrade halt-height upgrade (NOT a rolling restart). A mixed-binary window will produce an app-hash split — verified the hard way on devnet 2026-05-12.

Migration

None required — SupernodeMetricsState already exists; only its write path is restored. No state schema change.

Rollback

Revert this commit; pool→SN distribution returns to pre-bridge behavior (pays out zero). Chain state remains consistent.

Validation

  • Unit + integration tests: go test ./x/audit/... ./x/supernode/... → all green
  • Devnet (5-validator + 5-SN, lumera-devnet-1):
    • Built 1.12.0-cherrypick-pr140-2c5ee772 binary, deployed across all 5 validators
    • 5/5 SNs submit epoch_id reports with field 6 — no proto-decode errors
    • 20/20 cascade register+upload+download cycles end-to-end (sn-api-server → SDK → SN → chain), SHA-256 hash match on every download
    • Fee routing observed live per registration: 2% → supernode pool (module lumera167yww…), ~98% → active SN. 19 successful cascades grew pool from 0 → 4819 ulume.

Files

  • proto/lumera/audit/v1/audit.proto — field 6 added
  • x/audit/v1/keeper/msg_submit_epoch_report.go — validation + bridge call
  • x/audit/v1/keeper/msg_submit_epoch_report_cascade_bytes_test.go — new (10 invariant tests)
  • x/audit/v1/types/errors.go — new typed error
  • Regenerated: x/audit/v1/types/audit.pb.go, docs/static/openapi.yml

Observability

SubmitEpochReport already emits typed events for accepted/rejected reports. New rejection path logs the typed error.

Parent PR

Master-branch equivalent: #140

…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 mateeullahmalik merged commit c26b074 into 1.12.0 May 12, 2026
7 checks passed
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.

1 participant