Skip to content

[HIGH] get_top_players uses O(n²) selection sort with full Vec rebuilds — gas bomb that reverts on real leaderboards #16

Closed

Description

@Muyideen-js

[HIGH] get_top_players uses O(n²) selection sort with full Vec rebuilds — gas bomb that reverts on real leaderboards

Summary

get_top_players (leaderboard/src/lib.rs, lines ~361–432) sorts the top list with a selection sort where each swap rebuilds the entire Vec:

for i in 0..n {
    let mut max_idx = i;
    for j in (i + 1)..n { ... }
    if max_idx != i {
        // rebuild the whole Vec to swap two elements
        let mut rebuilt: Vec<PlayerEntry> = Vec::new(&env);
        for k in 0..n { ... }
        all = rebuilt;
    }
}

With MAX_TOP_PLAYERS = 50, the worst case is ~1225 comparisons and up to ~1225 full Vec rebuilds of 50 elements each — tens of thousands of allocations in Soroban's linear memory. This exceeds the gas/CPU budget on a full leaderboard, so get_top_players always reverts for real users. The comment even acknowledges it's O(n²) but the "optimization" (fewer rebuilds when already sorted) does not help the common case where points are interleaved.

Why it's unsolvable by a localized patch

  • The sort is on-read — every call re-sorts from scratch; there is no cached sorted order.
  • Soroban Vec is immutable — "swapping" requires a full rebuild, so any comparison-sort is O(n²) allocations.
  • Reducing MAX_TOP_PLAYERS changes the product and still leaves the O(n²) cost.
  • A correct fix requires maintaining a sorted index at write time (in upsert_top) or a heap/ordered structure, so reads are O(k) — a storage-model redesign.

The root problem is sorting on read with an immutable data structure. A correct fix needs a write-time-ordered index, which is a fundamental change to the leaderboard storage.

Activity

  1. added
    hardExtremely difficult to resolve
    unsolvableEffectively unsolvable by localized patch
    dosDenial of service
    on Aug 16, 2026
  2. grantfox-oss commented on Aug 16, 2026

    @grantfox-oss

    🦊 GrantFox — @pixels26 has been assigned to this issue as part of the Third Campaign campaign!

    Next steps:

    1. Open a Pull Request referencing this issue (e.g., Closes #16)
    2. Your PR will be reviewed by the SPulse-Org maintainers

    Good luck! Track your progress on GrantFox.

  3. Aycode01 commented on Aug 29, 2026

    @Aycode01
    Contributor

    Hi can I work on this

  4. grantfox-oss commented on Aug 29, 2026

    @grantfox-oss

    🦊 GrantFox — @Aycode01 has been assigned to this issue as part of the Third Campaign campaign!

    Next steps:

    1. Open a Pull Request referencing this issue (e.g., Closes #16)
    2. Your PR will be reviewed by the SPulse-Org maintainers

    Good luck! Track your progress on GrantFox.

  5. grantfox-oss commented on Aug 31, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @Aycode01's PR #200 was approved and merged by @Muyideen-js.

    🏆 @Aycode01: You earned 40 FoxPoints for this contribution! Your current tier: Builder (1,268 total points). Track your full progress on GrantFox.

    👏 Great work, @Aycode01! Keep contributing to SPulse-Org.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaigndosDenial of servicegas-optimizationGas / performancehardExtremely difficult to resolveleaderboardLeaderboard contractunsolvableEffectively unsolvable by localized patch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions