Status: Active Reference: Issue #263 Last updated: 2026-08-02 Audience: Backend consumers, operators, and contract contributors
- Overview
- Contract implementation
- Policy: offset semantics
- Policy: limit & page size
- Policy: end-of-history signalling
- Policy: overflow safety
- Policy: ordering & stability
- Canonical source of truth
The contract exposes SLA calculation history through a set of read-only
accessors backed by the append-only HISTORY_KEY vector
(apexchainx_calculator/src/history.rs, storage key HIST). This policy
defines how paginated history reads behave so that backend consumers can
page through arbitrarily large histories deterministically, without relying
on undocumented behaviour.
The canonical behaviour is the contract's actual return behaviour; this document exists to make that behaviour explicit and reviewable.
The paginated accessor is:
pub fn get_history_page(env: Env, offset: u32, limit: u32) -> Result<Vec<SLAResult>, SLAError>Implemented in two places that must stay in lockstep:
apexchainx_calculator/src/lib.rs— the#[contractimpl]entry point (the on-chain method consumers call).apexchainx_calculator/src/history.rs— the module-level helper.
Both read the full history vector, compute end = min(saturating_add(offset, limit), len),
and return the slice history[offset..end]. History is capped at
MAX_HISTORY_SIZE (1000) entries and is append-only; entries are never
reordered, so pagination is stable across calls.
offsetis the 0-based index of the first entry to return.- History is stored oldest-first (insertion order).
offset = 0is the earliest recorded result; the largest valid offset islen - 1. - An
offset >= len(including any offset on an empty history) returns an empty page — it is not an error. - Offsets are
u32. Extreme offsets such asu32::MAXare therefore representable and simply produce an empty page.
limitis the maximum number of entries returned per page.limitis not clamped to an upper bound. The effective page size ismin(limit, len - offset): alimitlarger than the remaining history returns everything that remains.- A page shorter than the requested
limittherefore signals that fewer entries remain than were asked for — the strongest end-of-history signal. limit == 0returns an empty page (zero items requested).limitisu32, so consumers may pass up tou32::MAXsafely (see overflow safety).
There are two equivalent end-of-history signals:
- A returned page with fewer than
limitentries (whenlimit > 0), or - An empty page (which is also the result of
offset >= lenorlimit == 0).
Consumers are encouraged to iterate with a fixed page size and stop on the first short page, which is exactly one extra call after the last full page and needs no special-casing for empty histories.
offset and limit are u32, so the naive computation offset + limit
can overflow (e.g. offset near u32::MAX, or limit = u32::MAX). The
implementation therefore uses saturating addition:
let end = offset.saturating_add(limit).min(len);Saturation guarantees that any page request is clamped to the real history length and can never wrap into a wrong slice or panic. Consumers do not need to pre-validate their offsets or limits for arithmetic safety.
- Entries are returned in insertion order (oldest first); the contract never reorders history.
- Pagination is stable across calls: identical
(offset, limit)inputs against the same history produce identical slices. - The accessor is read-only: it performs no storage writes, emits no events, and never mutates history. It is safe to call concurrently and repeatedly.
The contract implementation in apexchainx_calculator/src/lib.rs (and the
matching helper in apexchainx_calculator/src/history.rs) is the canonical
source of truth for this policy. If this document and the code ever disagree,
the code wins — update this document to match the code, and add a test in
apexchainx_calculator/src/tests.rs covering the divergent case.