Problem
get_full_audit_state (src/lib.rs) calls check_version once, then delegates to nine methods that each call it again and re-read the same instance storage:
pub fn get_full_audit_state(env: Env) -> Result<AuditState, SLAError> {
Self::check_version(&env)?;
let admin = Self::get_admin(env.clone())?; // check_version + storage read
let operator = Self::get_operator(env.clone())?; // check_version + storage read
let pending_admin = Self::get_pending_admin(env.clone())?;
let pending_operator = Self::get_pending_operator(env.clone())?;
let paused = Self::is_paused(env.clone())?;
let pause_info = Self::get_pause_info(env.clone())?;
let config_snapshot = Self::get_config_snapshot(env.clone())?; // 4 more config map reads
let stats = Self::get_stats(env.clone())?;
let result_schema = Self::get_result_schema(env.clone())?;
...
}
Soroban instance storage is read whole per key access, so this "one-shot bootstrap" issues ~10 version checks and many full-key deserializations for data that could be read once.
Consequences:
- The bootstrap envelope is not actually one-shot-cheap: the envelope exists so backends avoid N round-trips; internally it performs N reads + N version checks, so the RPC is cheap but the host work is the sum of all delegated reads.
- The version check is 10x redundant:
check_version is pure (reads VER); doing it ten times in one call is wasted work with no correctness benefit.
- The cost grows with each added field: extending
AuditState with another delegated getter adds another env.clone() + read + version check; nothing measures the envelope's cost (no read-budget test covers get_full_audit_state).
Root cause
The envelope was composed from existing getters rather than written as a single storage pass; the delegation pattern (clone env, delegate, check_version inside) was reused without considering the redundancy.
Why this is architecturally hard
- Rewriting the envelope as one storage pass requires reading each key directly (or adding internal helpers that skip
check_version — e.g. pub(crate) unchecked getters) — a refactor that must preserve the exact response semantics (including pause_info as Vec, the history_len full read — companion issues).
- The
env.clone() pattern is pervasive; the fix should establish whether internal composition should use unchecked helpers vs. public methods.
- Any read-budget enforcement (the
offchain/readCostRegression.ts companion issue) should cover this envelope, so the fix should produce a measurable cost model.
Acceptance criteria
Out of scope
The history_len full-history read (companion issue) and the pause_info representation (companion issue).
Getting started
Good first files to read: apexchainx_calculator/src/lib.rs (get_full_audit_state), apexchainx_calculator/src/audit_state.rs.
Problem
get_full_audit_state(src/lib.rs) callscheck_versiononce, then delegates to nine methods that each call it again and re-read the same instance storage:Soroban instance storage is read whole per key access, so this "one-shot bootstrap" issues ~10 version checks and many full-key deserializations for data that could be read once.
Consequences:
check_versionis pure (readsVER); doing it ten times in one call is wasted work with no correctness benefit.AuditStatewith another delegated getter adds anotherenv.clone()+ read + version check; nothing measures the envelope's cost (no read-budget test coversget_full_audit_state).Root cause
The envelope was composed from existing getters rather than written as a single storage pass; the delegation pattern (clone env, delegate, check_version inside) was reused without considering the redundancy.
Why this is architecturally hard
check_version— e.g.pub(crate)unchecked getters) — a refactor that must preserve the exact response semantics (includingpause_infoasVec, thehistory_lenfull read — companion issues).env.clone()pattern is pervasive; the fix should establish whether internal composition should use unchecked helpers vs. public methods.offchain/readCostRegression.tscompanion issue) should cover this envelope, so the fix should produce a measurable cost model.Acceptance criteria
get_full_audit_stateperforms a single version check and reads each storage key once.AuditStatetests pass).Out of scope
The
history_lenfull-history read (companion issue) and thepause_inforepresentation (companion issue).Getting started
just testGood first files to read:
apexchainx_calculator/src/lib.rs(get_full_audit_state),apexchainx_calculator/src/audit_state.rs.