Skip to content

feat(mix): cover traffic with constant rate#2243

Merged
chaitanyaprem merged 1 commit into
masterfrom
feat/cover-traffic
Apr 21, 2026
Merged

feat(mix): cover traffic with constant rate#2243
chaitanyaprem merged 1 commit into
masterfrom
feat/cover-traffic

Conversation

@chaitanyaprem
Copy link
Copy Markdown
Contributor

@chaitanyaprem chaitanyaprem commented Apr 8, 2026

Summary

Implements the cover traffic mechanism for the Mix Protocol as a pluggable component, following the same pattern as DelayStrategy.
Cover traffic ensures sender unobservability by emitting dummy Sphinx packets at a constant rate, making it impossible for an observer to distinguish cover traffic from locally originated messages.

This PR:

  • Adds the CoverTraffic abstract base type and ConstantRateCoverTraffic strategy (spec §7.1 RECOMMENDED)
  • Introduces SlotPool to manage the per-epoch R-slot budget shared across cover, local origination, and forwarding traffic
  • Integrates cover traffic into MixProtocol at four spec-defined touch points: cover packet transmission, non-cover slot claiming, epoch boundary handling, and cover packet reception at exit
  • Adds OnEpochChange callback support to SpamProtection for epoch boundary notifications (spec: mix-dos-protection §8.2.3)
  • Supports configurable batch pre-computation of cover packets staged for the next epoch

The spec this implements: vacp2p/rfc-index#311

Affected Areas

  • Protocol Logic
    • Mix protocol: new cover_traffic.nim module, integration into mix_protocol.nim (exit handler codec check, slot claiming in send/forward paths, init/stop
      wiring), epoch change support in spam_protection.nim

Compatibility & Downstream Validation

Cover traffic is opt-in. When not configured existing behavior is fully preserved.

The SpamProtection interface gains new methods (registerOnEpochChange, epochDurationSeconds, rateLimitBudget) with base implementations that are no-ops/return
defaults, so existing concrete implementations (e.g. RLN plugin) continue to compile without changes.

  • Waku (logos-delivery): follow-up PR to wire CoverTraffic into WakuMix.init and update the RLN plugin to call notifyEpochChange

Impact on Library Users

  • New optional parameter: MixProtocol.new and MixProtocol.init accept coverTraffic: Opt[CoverTraffic] (default Opt.none) — no migration required
  • New public types: CoverTraffic, ConstantRateCoverTraffic, SlotPool, PrebuiltCoverPacket, BuildCoverPacketProc, SendCoverPacketProc — all in
    libp2p/protocols/mix/cover_traffic
  • SpamProtection interface extended: Three new base methods added with default implementations — existing subclasses are unaffected
  • No breaking changes

Risk Assessment

  • Network behavior: When enabled, cover traffic consumes slots from the shared R-budget. Forwarded packets are dropped and locally originated messages fail when slots are exhausted (TODO: queue for next epoch)
  • Performance: Cover packet construction involves Sphinx wrapping and optional proof generation per emission. Pre-computation (configurable) amortizes this cost

Additional Notes

  • The RLN spam protection plugin mix-rln-spam-protection-plugin needs a separate PR to override epochDurationSeconds/rateLimitBudget and call
    notifyEpochChange on epoch transitions.
  • Cover traffic works independently of DoS protection with sensible defaults (R=100, P=60s) and an internal epoch timer fallback.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 8, 2026

Codecov Report

❌ Patch coverage is 69.66825% with 128 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.60%. Comparing base (11a9bb9) to head (fe79825).

Files with missing lines Patch % Lines
libp2p/protocols/mix/cover_traffic.nim 71.84% 67 Missing ⚠️
libp2p/protocols/mix/mix_protocol.nim 67.24% 57 Missing ⚠️
libp2p/protocols/mix/spam_protection.nim 60.00% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2243      +/-   ##
==========================================
- Coverage   72.66%   72.60%   -0.06%     
==========================================
  Files         166      167       +1     
  Lines       21435    21844     +409     
  Branches       20       20              
==========================================
+ Hits        15575    15860     +285     
- Misses       5860     5984     +124     
Files with missing lines Coverage Δ
libp2p/protocols/mix/spam_protection.nim 62.74% <60.00%> (+2.74%) ⬆️
libp2p/protocols/mix/mix_protocol.nim 79.41% <67.24%> (-4.22%) ⬇️
libp2p/protocols/mix/cover_traffic.nim 71.84% <71.84%> (ø)

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements opt-in Mix Protocol cover traffic as a pluggable strategy (constant-rate per spec), including shared per-epoch slot budgeting and integration hooks in MixProtocol and SpamProtection, plus accompanying unit/integration tests and new metrics.

Changes:

  • Add CoverTraffic base type, ConstantRateCoverTraffic strategy, and SlotPool budget management.
  • Integrate cover traffic into MixProtocol (cover emission/build/send hooks, slot claiming on send/forward, epoch-change propagation, exit handling).
  • Add cover-traffic-focused tests and Mix metrics; remove GossipSub interop test/binary code.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
libp2p/protocols/mix/cover_traffic.nim New cover traffic abstractions + constant-rate implementation with optional precomputation.
libp2p/protocols/mix/mix_protocol.nim Wires cover traffic into MixProtocol lifecycle, slot claiming paths, and cover packet build/send helpers.
libp2p/protocols/mix/spam_protection.nim Extends SpamProtection with epoch-change callbacks + epoch/budget query stubs.
libp2p/protocols/mix/mix_metrics.nim Adds counters/gauges for cover emission/reception and slot exhaustion.
tests/libp2p/mix/test_cover_traffic.nim Unit tests for SlotPool, ConstantRateCoverTraffic emission, precompute behavior, and lifecycle.
tests/libp2p/mix/component/test_cover_traffic.nim Component/integration tests validating cover packet validity, traversal, and slot exhaustion behavior.
tests/interop/test_gossipsub.nim Removed GossipSub interop tests.
interop/gossipsub/src/runner.nim Removed GossipSub interop script runner implementation.
interop/gossipsub/src/node.nim Removed GossipSub interop node utilities (keys/peer IDs/msg IDs).
interop/gossipsub/src/logger.nim Removed structured JSON logger for GossipSub interop.
interop/gossipsub/src/instructions.nim Removed GossipSub interop instruction parsing/types.
interop/gossipsub/peer.nim Removed GossipSub interop “peer” binary entrypoint.
interop/gossipsub/nim_peer.nimble Removed nimble manifest for the GossipSub interop binary.
interop/gossipsub/config.nims Removed build config for the GossipSub interop binary.

Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/cover_traffic.nim Outdated
Comment thread libp2p/protocols/mix/cover_traffic.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/spam_protection.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim
Copilot AI review requested due to automatic review settings April 10, 2026 06:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/cover_traffic.nim Outdated
@gmelodie gmelodie changed the title feat(mix): implement cover traffic with constant rate as per spec feat(mix): cover traffic with constant rate Apr 10, 2026
Copy link
Copy Markdown
Contributor

@gmelodie gmelodie left a comment

Choose a reason for hiding this comment

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

This PR is a PoC, and thus it should not be merged. In the future please wait until the spec is more mature to open a PR. Mature here doesn't necessarily mean merged in v1, but at it should at least have had some discussions and implemented feedback. Also, if you want feedback on a PoC, consider making the PR a draft, letting us know it's a PoC and then requesting the reviews.

Good work though!

Comment thread tests/libp2p/mix/component/test_cover_traffic.nim
Comment thread tests/libp2p/mix/component/test_cover_traffic.nim
Comment thread tests/libp2p/mix/test_cover_traffic.nim Outdated
Comment thread tests/libp2p/mix/test_cover_traffic.nim Outdated
Comment thread libp2p/protocols/mix/cover_traffic.nim Outdated
Comment on lines +39 to +42
type CoverPacket* = object
packet*: seq[byte]
firstHopPeerId*: PeerId
firstHopAddr*: MultiAddress
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
type CoverPacket* = object
packet*: seq[byte]
firstHopPeerId*: PeerId
firstHopAddr*: MultiAddress
type CoverPacket* = object
packet*: seq[byte]
firstHop*: (PeerId, seq[MultiAddress])

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

keeping separate fields for now. writeLp and getConn do use seq[MultiAddress] but we always resolve to a single supported address per mix node, so wrapping in @[multiAddr] at the boundary is fine. changing the type would ripple across callback types and call sites for no functional benefit.

Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
@github-project-automation github-project-automation Bot moved this from new to In Progress in nim-libp2p Apr 10, 2026
Copilot AI review requested due to automatic review settings April 10, 2026 16:49
Copilot AI review requested due to automatic review settings April 16, 2026 06:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Comment on lines +220 to +255
let built = buildRes.get()
let sendRes =
await ct.sendPacket(built.firstHopPeerId, built.firstHopAddr, built.packet)
if sendRes.isErr:
debug "Failed to send cover packet", err = sendRes.error
mix_cover_error.inc(labelValues = ["SEND_FAILED"])
else:
mix_cover_emitted.inc(labelValues = ["on_demand"])

proc emitCoverPacket*(
ct: ConstantRateCoverTraffic
) {.async: (raises: [CancelledError]).} =
if ct.enablePrecomputation and ct.slotPool.queuedCount > 0:
if not ct.slotPool.claimSlotForCover():
mix_slot_claim_rejected.inc(labelValues = ["cover"])
return
ct.slotPool.dequeue().withValue(pkt):
# Check if the prebuilt proof is still valid (e.g., Merkle root not stale)
if ct.validateProofToken != nil and pkt.proofToken.len > 0 and
not ct.validateProofToken(pkt.proofToken):
trace "Prebuilt cover packet has stale proof, rebuilding on-demand"
mix_cover_error.inc(labelValues = ["STALE_PROOF"])
# Reclaim the stale proof's messageId so it can be reused
if ct.reclaimProofToken != nil:
ct.reclaimProofToken(pkt.proofToken)
await ct.buildAndSendOnDemand()
return
else:
let sendRes =
await ct.sendPacket(pkt.firstHopPeerId, pkt.firstHopAddr, pkt.packet)
if sendRes.isErr:
debug "Failed to send pre-built cover packet", err = sendRes.error
mix_cover_error.inc(labelValues = ["SEND_FAILED"])
else:
mix_cover_emitted.inc(labelValues = ["prebuilt"])
return
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

When sendPacket returns an error, the cover packet was effectively discarded but its proofToken is not reclaimed. For spam-protection implementations where token represents a reserved/consumed slot (eg precomputed messageId), this can leak budget and cause premature slot exhaustion after transient send failures. Consider invoking reclaimProofToken (when set and token non-empty) on SEND_FAILED for both on-demand builds (built.proofToken) and prebuilt packets (pkt.proofToken).

Copilot uses AI. Check for mistakes.
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim
Comment thread libp2p/protocols/mix/cover_traffic.nim Outdated
Comment on lines +60 to +70
func new*(T: typedesc[SlotPool], totalSlots: int): T =
T(epoch: 0, totalSlots: totalSlots, coverQueue: initDeque[CoverPacket]())

func beginEpoch*(pool: SlotPool, epoch: uint64) =
## Clear stale cover packets and refill slots for the new epoch.
## Precomputed packets from the previous epoch are discarded because
## their proofs belong to the old epoch.
pool.epoch = epoch
pool.coverQueue = initDeque[CoverPacket]()
pool.coverClaimed = 0
pool.nonCoverClaimed = 0
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

SlotPool exposes several state-mutating routines as func (beginEpoch, claimSlotForCover, claimSlot, updateTotalSlots, addPacket, dequeue). In Nim, func implies noSideEffect, so assignments like pool.coverClaimed += 1 / pool.coverQueue.popFirst() will fail to compile under the effect system. These should be proc (or otherwise explicitly allow side effects) to match mutable APIs elsewhere in the codebase.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 16, 2026 11:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment thread libp2p/protocols/mix/mix_protocol.nim
Comment thread libp2p/protocols/mix/mix_protocol.nim
Comment thread libp2p/protocols/mix/mix_protocol.nim Outdated
Comment on lines +90 to +98
method registerOnEpochChange*(
self: SpamProtection, cb: EpochChangeCallback
) {.base, gcsafe, raises: [].} =
self.epochChangeCallbacks.add(cb)

proc notifyEpochChange*(self: SpamProtection, epoch: uint64) {.raises: [].} =
## Fire all registered epoch change callbacks.
for cb in self.epochChangeCallbacks:
cb(epoch)
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

registerOnEpochChange is a virtual method, but notifyEpochChange is a non-virtual proc that iterates epochChangeCallbacks directly. If a concrete SpamProtection overrides registerOnEpochChange (e.g., to forward registration elsewhere), notifyEpochChange won’t fire those callbacks. Consider making registerOnEpochChange a non-virtual proc, or make notifyEpochChange a method whose base implementation dispatches through the same override point.

Copilot uses AI. Check for mistakes.
Comment thread libp2p/protocols/mix/spam_protection.nim
Copilot AI review requested due to automatic review settings April 16, 2026 12:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

## for proof slot tracking.
let spamProtection = mixProto.spamProtection.valueOr:
return ok(packet)
return ok((packet, newSeq[byte]()))
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

When spamProtection is disabled, generateAndAppendProof returns ok((packet, newSeq[byte]())), which allocates a new empty seq on every call. This is on the hot path for sending/forwarding; consider returning a shared empty seq literal (e.g. @[] / default(seq[byte])) to avoid per-packet allocations.

Suggested change
return ok((packet, newSeq[byte]()))
return ok((packet, default(seq[byte])))

Copilot uses AI. Check for mistakes.
method stop*(ct: CoverTraffic) {.base, async: (raises: []).} =
raiseAssert "stop must be implemented by concrete cover traffic types"

method onEpochChange*(ct: CoverTraffic, epoch: uint64) {.base, gcsafe, raises: [].} =
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

CoverTraffic.onEpochChange calls slotPool.beginEpoch(epoch), which clears coverQueue and drops any queued precomputed packets. If those packets carry proofTokens from spam protection, they are discarded without calling reclaimProofToken, so implementations that track/lease proof slots via tokens may leak capacity/resources. Consider draining the existing queue and invoking ct.reclaimProofToken(token) (when set and non-empty) for each packet before clearing/refilling for the new epoch.

Suggested change
method onEpochChange*(ct: CoverTraffic, epoch: uint64) {.base, gcsafe, raises: [].} =
method onEpochChange*(ct: CoverTraffic, epoch: uint64) {.base, gcsafe, raises: [].} =
if not ct.reclaimProofToken.isNil:
while ct.slotPool.coverQueue.len > 0:
let discarded = ct.slotPool.coverQueue.popFirst()
if discarded.proofToken.len > 0:
ct.reclaimProofToken(discarded.proofToken)

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 21, 2026 13:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Comment on lines +406 to +408
proc(): Future[Result[tuple[packet: seq[byte], proofToken: seq[byte]], string]] {.
async
.} =
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The proc pragma formatting here ({. async .} split across lines) is inconsistent with the surrounding code and is likely to be rewritten by the repo formatter (nph), causing CI formatting failures. Please run nimble format or adjust this to the standard single-line pragma formatting used elsewhere in the file.

Suggested change
proc(): Future[Result[tuple[packet: seq[byte], proofToken: seq[byte]], string]] {.
async
.} =
proc(): Future[Result[tuple[packet: seq[byte], proofToken: seq[byte]], string]] {.async.} =

Copilot uses AI. Check for mistakes.
coverClaimed*: int
nonCoverClaimed*: int

proc new*(T: typedesc[SlotPool], totalSlots: int): T =
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

SlotPool.new is exported and currently accepts any totalSlots value without validation. Negative or zero values would make availableSlots incorrect (and claimSlotForCover / claimSlot behavior confusing). Consider asserting totalSlots > 0 here (consistent with ConstantRateCoverTraffic.new), or clamp/return an error if you want to allow SlotPool to be used directly as a public API.

Suggested change
proc new*(T: typedesc[SlotPool], totalSlots: int): T =
proc new*(T: typedesc[SlotPool], totalSlots: int): T {.raises: [AssertionDefect].} =
doAssert totalSlots > 0, "SlotPool totalSlots must be greater than zero"

Copilot uses AI. Check for mistakes.
Comment on lines +289 to +293
## Builds cover packets in batches and adds them to the coverQueue for the
## current epoch (same-epoch precomputation).
##
## Packets are built with proofs for the current epoch so their proof tokens
## can be reclaimed if the packet is discarded before sending.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The PR description mentions pre-computation "staged for the next epoch", but the implementation and comment here explicitly describe same-epoch precomputation and beginEpoch clears the queue on epoch change. Please either update the PR description to match the current behavior, or adjust the implementation if next-epoch staging is required by the spec/requirements.

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +214
proc unclaimCoverSlot(ct: ConstantRateCoverTraffic) =
## Return a cover slot on build/send failure so it can be retried.
if ct.slotPool.coverClaimed > 0:
ct.slotPool.coverClaimed -= 1

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

unclaimCoverSlot claims to return a slot on "build/send failure", but it is only invoked on build failures (send failures still consume a slot). Either update the comment to match the behavior, or call unclaimCoverSlot() on send failures as well if the intended behavior is to retry without consuming the epoch budget.

Copilot uses AI. Check for mistakes.
Comment thread tests/libp2p/mix/test_cover_traffic.nim Outdated
Comment on lines +168 to +170
asyncSpawn ct.start()
checkUntilTimeout:
ct.isRunning == true
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

In this test, asyncSpawn ct.start() launches an untracked future. The project guidelines discourage asyncSpawn unless the spawned Future is tracked, and here it's also unnecessary because ConstantRateCoverTraffic.start() doesn't block (it just sets up internal loops and returns). Prefer await ct.start() (or store the returned Future and await/cancel it in teardown) to avoid untracked tasks.

Suggested change
asyncSpawn ct.start()
checkUntilTimeout:
ct.isRunning == true
await ct.start()
check ct.isRunning == true

Copilot uses AI. Check for mistakes.
Adds constant-rate cover traffic emission and per-hop spam protection
proof token reuse for the Mix Protocol per spec sections 3-7 and 9.6.

Key changes:
- ConstantRateCoverTraffic: fixed-interval emission with slot pool budget
- Same-epoch precomputation with stale proof detection and rebuild
- Opaque ProofResult token for messageId reclaim on packet discard
- SlotPool: unified R-slot budget across cover/forward/origination
- SpamProtection: reclaimProofToken + isProofTokenValid methods
- Metrics: mix_cover_emitted, mix_cover_error, mix_slot_claim_rejected

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 14:17
@chaitanyaprem chaitanyaprem enabled auto-merge (squash) April 21, 2026 14:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment on lines +292 to +297
## Builds cover packets in batches and adds them to the coverQueue for the
## current epoch (same-epoch precomputation).
##
## Packets are built with proofs for the current epoch so their proof tokens
## can be reclaimed if the packet is discarded before sending.
while ct.running:
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

PR description says pre-computation is "staged for the next epoch", but this loop explicitly precomputes for the current epoch (and discards packets on epoch change). Either adjust implementation to build into a next-epoch queue, or update the PR description to match the current-epoch behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +1029 to +1033
doAssert not switch.rng.isNil, "Switch must have RNG initialized"

mixProto.mixNodeInfo = mixNodeInfo
mixProto.switch = switch
mixProto.rng = rng
mixProto.rng = switch.rng
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

MixProtocol.init now hard-asserts switch.rng is non-nil, but newSwitch defaults rng to nil (so callers constructing a Switch directly can still end up with a nil RNG). This is a behavior/API change from the previous fallback and can lead to assertions (or nil derefs if asserts are disabled). Consider either (a) restoring a safe fallback initialization here, (b) turning this into a clear error return/exception in an API that can signal failure, or (c) documenting/enforcing the non-nil RNG requirement at Switch construction time.

Copilot uses AI. Check for mistakes.
@chaitanyaprem chaitanyaprem merged commit e1bbda4 into master Apr 21, 2026
39 of 40 checks passed
@chaitanyaprem chaitanyaprem deleted the feat/cover-traffic branch April 21, 2026 15:47
@github-project-automation github-project-automation Bot moved this from In Progress to done in nim-libp2p Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants