Skip to content

Slashing Event Log Search Index Corruption Under Concurrent Index Write Operations #41

Description

@JamesEjembi

Slashing Event Log Search Index Corruption Under Concurrent Index Write Operations

Problem Statement

The slashing event log in src/components/slashing/SlashingEventLog.tsx supports full-text search across slashing event descriptions. The search index is built client-side using lunr.js and rebuilt whenever new events arrive. The rebuildIndex() function at line 85 clears the index and re-adds all events. When two slashing events arrive within the same 50ms window (common during mass slashing of colluding nodes), the first rebuildIndex() starts, is interrupted by the second call (which clears the index again), and both attempt to add events concurrently. The resulting index contains duplicate entries for some events and missing entries for others. The search functionality returns incorrect results: searching for a known slashed node's ID returns zero results, or returns duplicate results with incorrect scores.

State Invariants & Parameters

  • Search library: lunr.js (client-side full-text)
  • Max events in index: 1,000
  • Index rebuild time: 15ms per 100 events
  • Concurrent rebuilds: 2 overlapping
  • Search accuracy target: 100% recall and precision

Affected Code Paths

  • src/components/slashing/SlashingEventLog.tsx:80-120rebuildIndex() overlapping calls
  • src/utils/search/slashingIndex.ts:40-65 — Lunr index management
  • src/hooks/useSlashingStream.ts:50-75 — WebSocket events triggering rebuild

Resolution Blueprint

  1. Implement a queue-based index rebuild: instead of calling rebuildIndex() directly on each event, enqueue a rebuild request with a requestId. A single setTimeout(processQueue, 100) drains the queue and rebuilds once with all pending events.
  2. Use a generation counter: indexGeneration is incremented on each rebuild start. addToIndex() checks that event.generation === currentGeneration. Stale adds are discarded.
  3. Implement differential indexing: instead of clearing and rebuilding, add individual events to the existing index using lunr.Index.prototype.add(). This avoids the clear-and-rebuild race entirely.
  4. Add a stress test that fires 10 concurrent slashing events and verifies the search index returns exactly 10 results for a wildcard query.

Labels

  • Complexity: Hardcore
  • Layer: Core-Engine
  • Type: Race-Condition

Metadata

Metadata

Assignees

Labels

Complexity: HardcoreExtremely difficult, high-complexity engineering taskGrantFox OSSIssue tracked in GrantFox OSSLayer: Core-EngineCore engine layerMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignType: Race-ConditionConcurrency and race condition related issues

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions