Skip to content

Perf/batch shape optimization - #105

Open
Bigg770 wants to merge 4 commits into
OpenPeerX:mainfrom
Bigg770:perf/batch-shape-optimization
Open

Perf/batch shape optimization#105
Bigg770 wants to merge 4 commits into
OpenPeerX:mainfrom
Bigg770:perf/batch-shape-optimization

Conversation

@Bigg770

@Bigg770 Bigg770 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

issue fixed a performance inefficiency in the batch execution hot
path.

When a user submitted a batch of operations, the contract needed to know how
many swaps were in the batch — once to check the rate limit before executing,
and again to record the rate limit usage after executing. Both times it did
this by scanning the entire operation list with a filter().count() call. So for
every batch, the same list was walked twice for no reason, since the contents
never changed between those two points.

The fix pre-computes the shape of the batch — swap count, mint count, LP add
count, LP remove count — in a single pass before any execution begins, stores
the result, and reuses it in both places. The list is now walked exactly once
per batch regardless of size.

closes #66

Bigg770 added 3 commits July 18, 2026 10:11
Change pair_to_pool from Map<(Symbol,Symbol), u64> to
Map<(Symbol,Symbol), Vec<u64>> so multiple pools (e.g. different fee
tiers or depths) can be registered for the same token pair without
reverting.

find_best_route now iterates every pool in the list for both direct and
two-hop legs, selecting the one that produces the highest output for the
given amount_in.

Tests (lp_tests.rs):
- test_two_pools_same_pair_route_chooses_optimal: registers a shallow
  (1k) and a deep (100k) XLM/USDC pool; asserts the deep pool is chosen.
- test_register_second_pool_same_pair_succeeds: verifies that a second
  register_pool call for the same pair no longer reverts.
Add on-chain swap-size histogram published as a SwapDistribution event.

events.rs:
- SwapDistribution contracttype struct with four buckets:
  size_0_100 / size_100_1k / size_1k_10k / size_10k_plus + total_swaps.
- SWAP_COUNT_KEY and SWAP_BUCKETS_KEY instance-storage constants.
- Events::record_swap() increments counter and bucket, auto-emits the
  SwapDistribution event every SWAP_DISTRIBUTION_CADENCE (1 000) swaps.
- Events::emit_swap_distribution() for admin-triggered flush + bucket reset.
- Events::swap_count() helper for tests and analytics.

lib.rs:
- CounterContract::emit_swap_distribution() entry point (admin-gated).
- swap() now calls Events::record_swap() after every successful swap.

Also includes BatchShape optimisation (Issue OpenPeerX#3) and its tests — both
land in the same lib.rs file.

Tests (batch_tests.rs):
- test_swap_count_increments: asserts counter is 1 after one swap, 2 after two.
- test_admin_trigger_emit_swap_distribution: admin can trigger flush without panic.
- test_batch_shape_ten_op_batch_correct_counts: 10-op batch executes correctly.
- test_batch_shape_mixed_operations: mixed swap/mint batch executes correctly.
Replace the double filter-iteration pattern in execute_batch_atomic and
execute_batch_best_effort with a pre-computed BatchShape.

Problem: both functions called
  operations.iter().filter(|op| matches!(op, BatchOperation::Swap(…))).count()
twice — once for the rate-limit check and once for recording usage.

Fix: introduce BatchShape { swap_count, mint_count, lp_add_count,
lp_remove_count } computed in a single O(n) pass via BatchShape::compute().
The result is stored before the portfolio load and reused for both the
rate-limit gate and the record step, eliminating the redundant iteration.

Tests (batch_tests.rs):
- test_batch_shape_ten_op_batch_correct_counts: 10-op all-swap batch
  completes with operations_executed == 10.
- test_batch_shape_mixed_operations: 3 swaps + 2 mints returns
  operations_executed == 5 with no failures.

Note: BatchShape code lands in the same lib.rs commit as Issue OpenPeerX#2
because both touch the same file. This commit records the intent and
acceptance criteria.

Copy link
Copy Markdown
Contributor

Excellent perf pass on the batch shape — measurable win and the benchmark notes make the trade-offs easy to follow. CI is green (Quality, Build, Test). Thanks for the rigor. Merging 🚀

Copy link
Copy Markdown
Contributor

First — really nice work on the perf pass, the benchmark notes made the trade-offs easy to follow 👏

Heads up: while working through the queue, I merged PRs #101, #102, #103, #104-attempt, and #110 ahead of yours. Several of those modified lib.rs, events.rs, and batch_tests.rs, so this branch now has merge conflicts against the updated main.

Could you rebase onto the latest main and push? Once CI re-runs green on the rebased tip, I'll land it. Shout if the rebase gets tangled.

@Bigg770

Bigg770 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

all done sir
please can i be among the selected payers please

@Bigg770

Bigg770 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

@ameeribro4-sudo done

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PeerX Backlog # 66] Avoid double-iteration of the batch vec

2 participants