Skip to content

fix(api): cap allowlist processing per cycle to prevent unbounded refresh (#92) - #158

Merged
valoryyaa-byte merged 4 commits into
RWA-ToolKit:mainfrom
euniceamoni:fix/92-allowlist-page-size
Jul 28, 2026
Merged

fix(api): cap allowlist processing per cycle to prevent unbounded refresh (#92)#158
valoryyaa-byte merged 4 commits into
RWA-ToolKit:mainfrom
euniceamoni:fix/92-allowlist-page-size

Conversation

@euniceamoni

Copy link
Copy Markdown
Contributor

Closes #92.

Summary

A single asset with a very large compliance allowlist could make one refresh cycle take arbitrarily long, delaying all other assets. This change caps the allowlist work per asset per cycle and spreads the remainder across subsequent cycles.

Changes

  • Add DEFAULT_COMPLIANCE_PAGE_SIZE = 50 constant (configurable via RWA_COMPLIANCE_PAGE_SIZE env var). Each address costs 2 RPC calls (get_record + balance), bounding the per-cycle budget to 2 × page_size per asset regardless of allowlist size.
  • Add compliance_offsets: Arc<Mutex<HashMap<u64, usize>>> on AppState to persist each asset's position across cycles. The offset advances by page_size each cycle and wraps to 0 at the end, ensuring the full list is always covered over time.
  • Add next_compliance_offset() helper that atomically reads, advances, and wraps the offset.
  • Update index_compliance_and_holders to accept a page: &[String] slice plus prev_summary/prev_holders for incremental mid-scan merging. On wrap, stale accumulated data is discarded to prevent count drift.

Note: This PR depends on #91 (fix/91-per-asset-freshness) and should be merged after it. PR #154 has been closed and split into that PR and this one.

…it#91)

- Add `indexed_at_ledger: u32` and `index_error: Option<String>` to the
  Asset model so consumers can tell which assets are stale.
- Make per-asset indexing fully best-effort: a failed get_metadata or
  compliance read no longer aborts the whole refresh cycle. The previous
  snapshot's data is re-emitted with index_error set instead.
- indexed_at_ledger is taken from the latest_ledger returned by the
  per-asset get_metadata simulation — the tightest freshness signal
  available without a database.
- Dividend fallback now also re-uses previous data rather than Vec::new().

Closes RWA-ToolKit#91
…rward (RWA-ToolKit#92)

- Add DEFAULT_COMPLIANCE_PAGE_SIZE=50 constant (overridable via
  RWA_COMPLIANCE_PAGE_SIZE env var) bounding per-asset RPC work to
  2 × page_size calls per refresh cycle regardless of allowlist length.
- Add compliance_offsets: Arc<Mutex<HashMap<u64,usize>>> to AppState with
  next_compliance_offset() helper that advances the per-asset cursor and
  wraps back to 0 after the last page.
- Rewrite index_compliance_and_holders to operate on a &[String] page
  slice and accept prev_summary/prev_holders for mid-scan carry-forward.
- Update refresh() call-site: fetches get_allowlist once, slices to the
  current page, carries forward accumulated summary/holders mid-scan and
  resets on wrap. All failure paths use labeled-block early-exit.

Closes RWA-ToolKit#92
@valoryyaa-byte
valoryyaa-byte merged commit e46061d into RWA-ToolKit:main Jul 28, 2026
1 check failed
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.

api: no limit on allowlist size processed per asset — a huge allowlist can make one refresh unbounded

2 participants