From 928075adad2044363c9f32c886630add9de617bf Mon Sep 17 00:00:00 2001 From: d3vobed Date: Mon, 22 Jun 2026 02:17:50 +0100 Subject: [PATCH] =?UTF-8?q?perf(#34):=20hoist=20find=5Fnext=5Fpending=5Fin?= =?UTF-8?q?dex=20to=20eliminate=20O(N=C2=B2)=20gas=20complexity=20in=20get?= =?UTF-8?q?=5Fall=5Fmilestones=5Fview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_all_milestones_view called views::get_milestone_by_index per milestone, and get_milestone_by_index invoked find_next_pending_index which linearly scanned every milestone to find the first non-released one. With N milestones this produced N + (N × N) ≈ N² storage reads. Fix: call find_next_pending_index once at the top of get_all_milestones_view and inline the MilestoneView construction in the loop, reusing the precomputed value for is_next_pending. Behavioural semantics of is_next_pending are unchanged — identical comparison, identical result. All 142 tests pass, including existing snapshot fixtures. Closes #34 --- campaign/src/get_all_milestones.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/campaign/src/get_all_milestones.rs b/campaign/src/get_all_milestones.rs index 7d0a8d4..8891951 100644 --- a/campaign/src/get_all_milestones.rs +++ b/campaign/src/get_all_milestones.rs @@ -1,8 +1,8 @@ use soroban_sdk::{panic_with_error, Env, Vec}; -use crate::storage::get_campaign; +use crate::storage::{get_campaign, get_milestone}; use crate::types::Error; -use crate::views::{self, MilestoneView}; +use crate::views::{find_next_pending_index, MilestoneView}; /// Issue #200 – Returns enriched views for ALL milestones in the campaign. /// @@ -16,9 +16,21 @@ pub fn get_all_milestones_view(env: &Env) -> Vec { let campaign = get_campaign(env).unwrap_or_else(|| panic_with_error!(env, Error::NotInitialized)); + let next_pending = find_next_pending_index(env); + let mut result: Vec = Vec::new(env); for i in 0..campaign.milestone_count { - result.push_back(views::get_milestone_by_index(env, i)); + let data = get_milestone(env, i) + .unwrap_or_else(|| panic_with_error!(env, Error::MilestoneNotFound)); + let pending_release = data.pending_release(); + let is_fully_released = data.is_fully_released(); + let is_next_pending = next_pending == i; + result.push_back(MilestoneView { + data, + pending_release, + is_fully_released, + is_next_pending, + }); } result }