Skip to content

Redesign seeding logic: LRU-based caching with byte budgets #2231

@sanity

Description

@sanity

Problem

The current seeding logic in SeedingManager::should_seed() uses ad-hoc thresholds that don't reflect principled design:

const CACHING_DISTANCE: f64 = 0.05;  // Magic number
const MAX_SEEDING_CONTRACTS: usize = 100;  // Arbitrary count
const MIN_SEEDING_CONTRACTS: usize = 25;   // More arbitrary counts

The three-tier decision tree (always seed below 25, distance-check between 25-100, score-based above 100) conflates storage limits with proximity requirements. It also treats all contracts equally regardless of their actual resource consumption.

Current Behavior

  1. Below 25 contracts: seed everything (ignores distance)
  2. 25-99 contracts: seed if distance < 0.05 (magic threshold)
  3. At 100 contracts: score-based eviction (proximity scoring)

This doesn't account for:

  • Contract state size (1KB vs 10MB treated the same)
  • Actual demand (no connection to subscription activity)
  • Network maturity (young networks with few contracts should cache broadly)

Proposed Design

Replace the count-based system with byte-budget LRU caching:

seed_pool_budget = X bytes (configurable)

on access (GET/PUT/SUBSCRIBE):
  add contract to seed pool, refresh LRU position
  while seed_pool_size > seed_pool_budget:
    evict least recently accessed contract

on eviction:
  if no downstream subscribers:
    unsubscribe from upstream

Key Properties

  1. Self-regulating: Proximity emerges naturally from routing - peers near a contract see more GETs, keeping it fresh
  2. Resource-aware: Large contracts consume more budget, may displace multiple small ones
  3. Demand-driven: Contracts with active subscribers never evict; inactive contracts age out
  4. Manipulation-resistant: Only GET/PUT/SUBSCRIBE refresh position, not UPDATE (which contract creators control)

Subscription Chain Cascade

When the last subscriber unsubscribes, the contract enters the LRU cache. The peer remains subscribed upstream until the contract is evicted. This creates a "sticky" subscription that:

  • Allows fast resubscription if someone subscribes again soon
  • Eventually cascades unsubscription up the tree as each hop evicts
  • Self-regulates: busy networks evict faster, quiet networks retain longer

Testing Requirements

This is critical infrastructure. The PR must include comprehensive tests:

Unit Tests

  • LRU eviction by byte budget
  • Access type tracking (GET/PUT/SUBSCRIBE refresh, UPDATE doesn't)
  • Time-based ordering with MockTimeSource
  • Subscription chain formation and cascade

Integration Tests

  • Cache behavior across multi-peer network
  • Eviction under pressure
  • Subscription persistence in LRU window
  • Chain collapse timing

Infrastructure Needed

  • Wire TimeSource trait into seeding logic
  • Add test-only cache inspection APIs
  • Configurable cache budget for testing

Related

Migration

The new logic should be backward-compatible in behavior for typical workloads. The main observable difference:

  • Contracts may persist longer after subscribers leave (LRU window)
  • Large contracts may evict sooner than small ones (byte-aware)

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-contractsArea: Contract runtime, SDK, and executionA-networkingArea: Networking, ring protocol, peer discoveryE-hardExperience needed to fix/implement: Hard / a lotS-needs-designStatus: Needs architectural design or RFCT-enhancementType: Improvement to existing functionality

    Type

    No type

    Projects

    Status

    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions