From de973eb4b0a208de3bbc6514f0631d638afed98e Mon Sep 17 00:00:00 2001 From: nanlebenthel-web Date: Sun, 21 Jun 2026 09:49:45 +0100 Subject: [PATCH] feat(contracts): add credential performance benchmarks and optimize storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a benchmark suite for the credential (Verification) contract and fix the storage scaling bottleneck it surfaced. - contracts/src/benchmarks.rs: measure per-operation budget (CPU instructions / memory bytes via env.budget()), execution time, and load behaviour. The benchmarks run as ordinary `cargo test` tests and assert resource ceilings, so they double as regression guards. - Bottleneck found: per-credential records were stored in instance storage, which serialises the entire contract data set on every call — O(n) per op, O(n^2) in aggregate (the 100th credential cost ~51x the 1st). - Optimization: move per-credential data to persistent storage keyed individually via a typed DataKey enum, with TTL bumping; keep only the bounded counter in instance storage. Public API is unchanged. N=100 batch cost drops 6.6x (CPU) and 4.0x (memory); reads get 26-30% cheaper. - docs/PERFORMANCE.md: methodology, before/after results, and remaining recommendations. README points to it. Closes #100 --- .gitignore | 5 + README.md | 3 + contracts/src/benchmarks.rs | 311 ++++++++++ contracts/src/lib.rs | 3 + contracts/src/verification.rs | 177 +++--- .../test_full_credential_lifecycle.1.json | 268 +++++---- .../test_get_verification_by_identity.1.json | 268 +++++---- .../test_get_verification_status.1.json | 268 +++++---- .../test_is_verification_valid.1.json | 323 +++++++---- ...erifications_independent_revocation.1.json | 529 ++++++++++------- .../test_revocation_list_maintenance.1.json | 535 +++++++++++------- .../test_revocation_status_updates.1.json | 323 +++++++---- .../test_revoke_rejected_verification.1.json | 383 ++++++++----- ...test_revoke_verification_credential.1.json | 323 +++++++---- ...est_submit_and_approve_verification.1.json | 268 +++++---- ...test_submit_and_reject_verification.1.json | 328 +++++++---- docs/PERFORMANCE.md | 129 +++++ 17 files changed, 2968 insertions(+), 1476 deletions(-) create mode 100644 contracts/src/benchmarks.rs create mode 100644 docs/PERFORMANCE.md diff --git a/.gitignore b/.gitignore index 0eb34d22..9e01f12c 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,11 @@ yarn-error.log* contracts/target/ Cargo.lock +# Benchmark test snapshots are large generated artifacts (load tests create +# hundreds of ledger entries) — not worth tracking. Integration-test snapshots +# are still tracked. +contracts/test_snapshots/benchmarks/ + # Database *.db *.sqlite diff --git a/README.md b/README.md index b6b30c9b..5ca4f52f 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,9 @@ A decentralized health credential platform built on the Stellar Soroban Smart Co - **Platform**: Stellar Soroban - **Build Tool**: Cargo - **Testing**: Soroban SDK +- **Performance**: Budget/gas, execution-time and load benchmarks for the + credential contract — see [`docs/PERFORMANCE.md`](docs/PERFORMANCE.md). Run with + `cargo test --features testutils benchmarks -- --nocapture`. ### DevOps - **Version Control**: Git diff --git a/contracts/src/benchmarks.rs b/contracts/src/benchmarks.rs new file mode 100644 index 00000000..07fcf056 --- /dev/null +++ b/contracts/src/benchmarks.rs @@ -0,0 +1,311 @@ +//! Performance benchmarks for the credential (`Verification`) contract. +//! +//! These benchmarks measure on-host resource usage (CPU instructions and +//! memory bytes via [`Env::budget`]) and wall-clock execution time for every +//! credential operation, plus load tests that exercise the contract under a +//! growing number of records. +//! +//! Run them with: +//! +//! ```text +//! cargo test --features testutils benchmarks -- --nocapture +//! ``` +//! +//! The `--nocapture` flag is required to see the printed measurement tables. +//! Without it the benchmarks still run and assert that costs stay within the +//! Soroban per-transaction resource limits, so they double as regression +//! guards. +//! +//! Caveat: when run natively (as Rust, not compiled to Wasm) the host +//! under-estimates CPU and memory relative to on-chain execution. The numbers +//! here are therefore a *relative* baseline for comparing operations and +//! catching regressions, not an exact prediction of mainnet fees. See +//! `docs/PERFORMANCE.md` for the methodology and recorded results. + +extern crate std; + +use soroban_sdk::{testutils::Address as _, Address, BytesN, Env, String}; +use std::time::Instant; + +use crate::verification::{Verification, VerificationClient}; + +// Soroban network per-transaction resource limits (Protocol 21). Native +// metering under-estimates real Wasm execution, so every operation should sit +// comfortably below these ceilings; the asserts catch pathological regressions. +const TX_CPU_LIMIT: u64 = 100_000_000; +const TX_MEM_LIMIT: u64 = 40 * 1024 * 1024; // 40 MiB + +fn setup() -> (Env, VerificationClient<'static>, Address) { + let env = Env::default(); + env.mock_all_auths(); + // Remove the default per-transaction budget cap so load tests can perform + // many operations back-to-back; we re-measure isolated costs by resetting + // the budget (which also zeroes the consumption tracker) before each op. + env.budget().reset_unlimited(); + let contract_id = env.register_contract(None, Verification {}); + let client = VerificationClient::new(&env, &contract_id); + let verifier = Address::generate(&env); + (env, client, verifier) +} + +/// Reset the metered budget so the next operation is measured in isolation. +/// `reset_unlimited` keeps tracking consumption but removes the limit so load +/// tests that perform many operations back-to-back never trip the cap. +fn reset_budget(env: &Env) { + let mut budget = env.budget(); + budget.reset_unlimited(); +} + +/// Read the CPU instructions and memory bytes consumed since the last reset. +fn consumed(env: &Env) -> (u64, u64) { + let budget = env.budget(); + (budget.cpu_instruction_cost(), budget.memory_bytes_cost()) +} + +fn report_op(name: &str, cpu: u64, mem: u64) { + std::println!( + " {:<34} cpu_insns = {:>12} mem_bytes = {:>10}", + name, + cpu, + mem + ); + // Regression guard: a single credential operation must stay well within + // the per-transaction network limits. + assert!(cpu > 0, "{name}: expected non-zero CPU cost"); + assert!( + cpu < TX_CPU_LIMIT, + "{name}: CPU cost {cpu} exceeded tx limit {TX_CPU_LIMIT}" + ); + assert!( + mem < TX_MEM_LIMIT, + "{name}: memory cost {mem} exceeded tx limit {TX_MEM_LIMIT}" + ); +} + +fn report_load(name: &str, n: u64, cpu: u64, mem: u64, elapsed_secs: f64) { + let per_op_us = if n > 0 { + (elapsed_secs * 1_000_000.0) / n as f64 + } else { + 0.0 + }; + std::println!( + " {:<34} n = {:>4} total_cpu = {:>14} total_mem = {:>12} wall = {:>8.3}ms per_op = {:>8.1}us", + name, + n, + cpu, + mem, + elapsed_secs * 1000.0, + per_op_us + ); +} + +fn proof(env: &Env) -> BytesN<32> { + BytesN::from_array(env, &[7u8; 32]) +} + +fn commitment(env: &Env) -> BytesN<32> { + BytesN::from_array(env, &[9u8; 32]) +} + +// ── Per-operation gas (budget) benchmarks ────────────────────────────────── + +#[test] +fn bench_per_operation_costs() { + let (env, client, verifier) = setup(); + let p = proof(&env); + let c = commitment(&env); + + std::println!("\n[credential per-operation budget cost]"); + + // submit_proof — create a credential proof. + reset_budget(&env); + let id = client.submit_proof(&1u64, &verifier, &p, &c); + let (cpu, mem) = consumed(&env); + report_op("submit_proof", cpu, mem); + + // approve_verification — approve a pending credential. + reset_budget(&env); + client.approve_verification(&id); + let (cpu, mem) = consumed(&env); + report_op("approve_verification", cpu, mem); + + // get_verification — read the full record. + reset_budget(&env); + let _ = client.get_verification(&id); + let (cpu, mem) = consumed(&env); + report_op("get_verification (read)", cpu, mem); + + // get_verification_status — read just the status string. + reset_budget(&env); + let _ = client.get_verification_status(&id); + let (cpu, mem) = consumed(&env); + report_op("get_verification_status (read)", cpu, mem); + + // is_verification_valid — validity check (status + revocation). + reset_budget(&env); + let _ = client.is_verification_valid(&id); + let (cpu, mem) = consumed(&env); + report_op("is_verification_valid (read)", cpu, mem); + + // revoke_verification — revoke a credential (also appends to the + // revocation list, see the load benchmark below). + reset_budget(&env); + client.revoke_verification(&id, &String::from_str(&env, "compromised")); + let (cpu, mem) = consumed(&env); + report_op("revoke_verification", cpu, mem); + + // reject_verification — reject a (different) pending credential. + let id2 = client.submit_proof(&2u64, &verifier, &p, &c); + reset_budget(&env); + client.reject_verification(&id2, &String::from_str(&env, "invalid proof")); + let (cpu, mem) = consumed(&env); + report_op("reject_verification", cpu, mem); +} + +#[test] +fn bench_full_lifecycle_cost() { + let (env, client, verifier) = setup(); + let p = proof(&env); + let c = commitment(&env); + + std::println!("\n[credential full lifecycle: submit -> approve -> revoke]"); + + reset_budget(&env); + let id = client.submit_proof(&42u64, &verifier, &p, &c); + client.approve_verification(&id); + client.revoke_verification(&id, &String::from_str(&env, "rotated")); + let (cpu, mem) = consumed(&env); + report_op("submit+approve+revoke", cpu, mem); +} + +// ── Execution-time benchmarks ────────────────────────────────────────────── + +#[test] +fn bench_execution_time() { + let (env, client, verifier) = setup(); + let p = proof(&env); + let c = commitment(&env); + + std::println!("\n[credential execution time]"); + + const ITERS: u64 = 200; + + // Time submit_proof across many calls. + let start = Instant::now(); + for i in 0..ITERS { + client.submit_proof(&i, &verifier, &p, &c); + } + let elapsed = start.elapsed().as_secs_f64(); + report_load("submit_proof", ITERS, 0, 0, elapsed); + + // Time a read-heavy op (is_verification_valid) across many calls. + let id = client.submit_proof(&9_999u64, &verifier, &p, &c); + client.approve_verification(&id); + let start = Instant::now(); + for _ in 0..ITERS { + let _ = client.is_verification_valid(&id); + } + let elapsed = start.elapsed().as_secs_f64(); + report_load("is_verification_valid", ITERS, 0, 0, elapsed); +} + +// ── Load tests ───────────────────────────────────────────────────────────── + +#[test] +fn bench_load_create_many_credentials() { + std::println!("\n[load: create N credentials]"); + + let mut totals: std::vec::Vec<(u64, u64)> = std::vec::Vec::new(); // (n, cpu) + + for &n in [10u64, 50, 100].iter() { + // Fresh contract instance per batch so each measurement is independent. + let (env, client, verifier) = setup(); + let p = proof(&env); + let c = commitment(&env); + + reset_budget(&env); + let start = Instant::now(); + for i in 0..n { + client.submit_proof(&i, &verifier, &p, &c); + } + let elapsed = start.elapsed().as_secs_f64(); + let (cpu, mem) = consumed(&env); + report_load("submit_proof xN", n, cpu, mem, elapsed); + totals.push((n, cpu)); + + // Sanity: the contract really did store all N records. + let _ = client.get_verification(&n); // verification ids are 1..=n + } + + // Regression guard against re-introducing the instance-storage bottleneck. + // + // With per-credential data in persistent storage, growing the batch 10x + // (n=10 -> n=100) costs ~33x here (the residual super-linear factor is a + // native test-host artifact — see the module/docs note: the in-memory host + // re-snapshots the whole ledger each invocation). With the data back in + // *instance* storage the same 10x growth cost ~89x. A 6x-over-linear + // ceiling cleanly sits between the two, so this only fires if the storage + // model regresses. + let (n_small, cpu_small) = totals[0]; + let (n_big, cpu_big) = totals[totals.len() - 1]; + let size_ratio = n_big / n_small; // 10x + let linear = cpu_small.saturating_mul(size_ratio); + assert!( + cpu_big <= linear.saturating_mul(6), + "submit_proof cost is scaling like instance storage (O(n^2) regression): \ + n={n_small} -> {cpu_small} cpu, n={n_big} -> {cpu_big} cpu" + ); +} + +/// Shows the impact of the storage optimisation: because each credential lives +/// in its own persistent entry, the marginal cost of creating a credential no +/// longer scales with the total credential count the way instance storage did. +/// We compare the cost of the 1st credential against the 100th in the same +/// contract. +/// +/// Recorded (native test host, see docs/PERFORMANCE.md): +/// * instance storage : #1 ≈ 57k cpu, #100 ≈ 2.9M cpu (~51x) +/// * persistent storage: #1 ≈ 84k cpu, #100 ≈ 0.77M cpu (~9x) +/// +/// On-chain the persistent path is O(1) per op (independent ledger entries); +/// the ~9x residual is the test host re-snapshotting all entries each call. +#[test] +fn bench_submit_proof_scaling() { + let (env, client, verifier) = setup(); + let p = proof(&env); + let c = commitment(&env); + + std::println!("\n[scaling: submit_proof cost vs existing credential count]"); + + // Cost of the very first credential. + reset_budget(&env); + client.submit_proof(&0u64, &verifier, &p, &c); + let (first_cpu, first_mem) = consumed(&env); + report_op("submit_proof #1 (0 existing)", first_cpu, first_mem); + + // Grow the contract to 99 stored credentials. + for i in 1..99u64 { + client.submit_proof(&i, &verifier, &p, &c); + } + + // Cost of the 100th credential, with 99 already stored. + reset_budget(&env); + client.submit_proof(&99u64, &verifier, &p, &c); + let (hundredth_cpu, hundredth_mem) = consumed(&env); + report_op( + "submit_proof #100 (99 existing)", + hundredth_cpu, + hundredth_mem, + ); + + // Regression guard: with persistent storage the 100th credential costs + // ~9x the 1st on the native host; with instance storage it was ~51x. A 20x + // ceiling separates the two. + assert!( + hundredth_cpu <= first_cpu.saturating_mul(20), + "submit_proof cost grows with stored credential count like instance storage: \ + #1={first_cpu} cpu, #100={hundredth_cpu} cpu" + ); + assert!(hundredth_cpu < TX_CPU_LIMIT); + assert!(hundredth_mem < TX_MEM_LIMIT); +} diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs index cdbe307d..8326ce1f 100644 --- a/contracts/src/lib.rs +++ b/contracts/src/lib.rs @@ -13,6 +13,9 @@ mod upgrade_tests; #[cfg(test)] mod integration_tests; +#[cfg(test)] +mod benchmarks; + pub use access_control::AccessControl; pub use data_sharing::DataSharing; pub use errors::Error; diff --git a/contracts/src/verification.rs b/contracts/src/verification.rs index b143dc62..83410375 100644 --- a/contracts/src/verification.rs +++ b/contracts/src/verification.rs @@ -21,6 +21,37 @@ pub enum VerificationEvent { VerificationRevoked, } +/// Typed storage keys. +/// +/// Per-credential entries (`Record`, `IdentityIndex`, `RejectReason`) and the +/// `RevokedList` live in **persistent** storage so that each operation only +/// reads and writes its own entry. They were previously kept in *instance* +/// storage, which serialises the contract's entire data set on every call and +/// therefore made each credential operation cost grow linearly with the total +/// number of stored credentials (O(n) per op, O(n²) overall). See +/// `docs/PERFORMANCE.md` and the `benchmarks` module for the measured impact. +/// +/// Only the monotonic `Counter` remains in instance storage — it is a single, +/// bounded value that every `submit_proof` must touch anyway. +#[contracttype] +pub enum DataKey { + Counter, + Record(u64), + IdentityIndex(u64), + RejectReason(u64), + RevokedList, +} + +// Persistent-entry time-to-live, expressed in ledgers (~5s each on Stellar). +// Entries are extended back up to ~31 days whenever they are read or written so +// active credentials are not archived out from under their owners. +const PERSISTENT_TTL_THRESHOLD: u32 = 17_280; // ~1 day +const PERSISTENT_TTL_EXTEND: u32 = 535_680; // ~31 days + +// Instance-entry TTL (only holds the bounded counter). +const INSTANCE_TTL_THRESHOLD: u32 = 17_280; // ~1 day +const INSTANCE_TTL_EXTEND: u32 = 535_680; // ~31 days + #[contract] pub struct Verification; @@ -38,7 +69,7 @@ impl Verification { let verification_id = env .storage() .instance() - .get::<_, u64>(&"verification_counter") + .get::<_, u64>(&DataKey::Counter) .unwrap_or(0u64) + 1; @@ -56,30 +87,25 @@ impl Verification { env.storage() .instance() - .set(&"verification_counter", &verification_id); - env.storage() - .instance() - .set(&(verification_id, "record"), &record); - env.storage() - .instance() - .set(&(identity_id, "verification"), &verification_id); + .set(&DataKey::Counter, &verification_id); + bump_instance(env); + + write_record(env, verification_id, &record); + + let index_key = DataKey::IdentityIndex(identity_id); + env.storage().persistent().set(&index_key, &verification_id); + bump_persistent(env, &index_key); verification_id } pub fn approve_verification(env: &Env, verification_id: u64) -> Result<(), Error> { - let mut record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; + let mut record = read_record(env, verification_id)?; record.verifier.require_auth(); record.status = String::from_str(env, "approved"); - env.storage() - .instance() - .set(&(verification_id, "record"), &record); + write_record(env, verification_id, &record); Ok(()) } @@ -88,45 +114,36 @@ impl Verification { verification_id: u64, reason: String, ) -> Result<(), Error> { - let mut record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; + let mut record = read_record(env, verification_id)?; record.verifier.require_auth(); record.status = String::from_str(env, "rejected"); - env.storage() - .instance() - .set(&(verification_id, "record"), &record); - env.storage() - .instance() - .set(&(verification_id, "reason"), &reason); + write_record(env, verification_id, &record); + + let reason_key = DataKey::RejectReason(verification_id); + env.storage().persistent().set(&reason_key, &reason); + bump_persistent(env, &reason_key); Ok(()) } pub fn get_verification(env: &Env, verification_id: u64) -> Result { - env.storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound) + read_record(env, verification_id) } pub fn get_verification_by_identity(env: &Env, identity_id: u64) -> Result { - env.storage() - .instance() - .get(&(identity_id, "verification")) - .ok_or(Error::VerificationNotFound) - } - - pub fn get_verification_status(env: &Env, verification_id: u64) -> Result { - let record: VerificationRecord = env + let index_key = DataKey::IdentityIndex(identity_id); + let verification_id: u64 = env .storage() - .instance() - .get(&(verification_id, "record")) + .persistent() + .get(&index_key) .ok_or(Error::VerificationNotFound)?; + bump_persistent(env, &index_key); + Ok(verification_id) + } + pub fn get_verification_status(env: &Env, verification_id: u64) -> Result { + let record = read_record(env, verification_id)?; Ok(record.status) } @@ -135,11 +152,7 @@ impl Verification { verification_id: u64, reason: String, ) -> Result<(), Error> { - let mut record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; + let mut record = read_record(env, verification_id)?; record.verifier.require_auth(); @@ -147,21 +160,20 @@ impl Verification { record.revoked_at = env.ledger().timestamp(); record.revocation_reason = reason; - env.storage() - .instance() - .set(&(verification_id, "record"), &record); + write_record(env, verification_id, &record); // Add to revocation list let mut revoked_list: Vec = env .storage() - .instance() - .get(&"revoked_verifications") + .persistent() + .get(&DataKey::RevokedList) .unwrap_or(Vec::new(env)); revoked_list.push_back(verification_id); env.storage() - .instance() - .set(&"revoked_verifications", &revoked_list); + .persistent() + .set(&DataKey::RevokedList, &revoked_list); + bump_persistent(env, &DataKey::RevokedList); // Emit revocation event env.events().publish( @@ -173,12 +185,7 @@ impl Verification { } pub fn is_verification_revoked(env: &Env, verification_id: u64) -> Result { - let record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; - + let record = read_record(env, verification_id)?; Ok(record.revoked) } @@ -186,29 +193,53 @@ impl Verification { env: &Env, verification_id: u64, ) -> Result<(bool, u64, String), Error> { - let record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; - + let record = read_record(env, verification_id)?; Ok((record.revoked, record.revoked_at, record.revocation_reason)) } pub fn get_revoked_verifications(env: &Env) -> Vec { env.storage() - .instance() - .get(&"revoked_verifications") + .persistent() + .get(&DataKey::RevokedList) .unwrap_or(Vec::new(env)) } pub fn is_verification_valid(env: &Env, verification_id: u64) -> Result { - let record: VerificationRecord = env - .storage() - .instance() - .get(&(verification_id, "record")) - .ok_or(Error::VerificationNotFound)?; - + let record = read_record(env, verification_id)?; Ok(record.status == String::from_str(env, "approved") && !record.revoked) } } + +// ── Storage helpers ───────────────────────────────────────────────────────── + +/// Read a credential record from persistent storage and extend its TTL so an +/// actively-used credential is not archived. +fn read_record(env: &Env, verification_id: u64) -> Result { + let key = DataKey::Record(verification_id); + let record: VerificationRecord = env + .storage() + .persistent() + .get(&key) + .ok_or(Error::VerificationNotFound)?; + bump_persistent(env, &key); + Ok(record) +} + +/// Persist a credential record and extend its TTL. +fn write_record(env: &Env, verification_id: u64, record: &VerificationRecord) { + let key = DataKey::Record(verification_id); + env.storage().persistent().set(&key, record); + bump_persistent(env, &key); +} + +fn bump_persistent(env: &Env, key: &DataKey) { + env.storage() + .persistent() + .extend_ttl(key, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND); +} + +fn bump_instance(env: &Env) { + env.storage() + .instance() + .extend_ttl(INSTANCE_TTL_THRESHOLD, INSTANCE_TTL_EXTEND); +} diff --git a/contracts/test_snapshots/integration_tests/test_full_credential_lifecycle.1.json b/contracts/test_snapshots/integration_tests/test_full_credential_lifecycle.1.json index fa3e1a79..16a8f1dc 100644 --- a/contracts/test_snapshots/integration_tests/test_full_credential_lifecycle.1.json +++ b/contracts/test_snapshots/integration_tests/test_full_credential_lifecycle.1.json @@ -319,6 +319,169 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -342,110 +505,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -460,7 +524,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -963,7 +1027,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_get_verification_by_identity.1.json b/contracts/test_snapshots/integration_tests/test_get_verification_by_identity.1.json index 8a88063b..43cb4dcc 100644 --- a/contracts/test_snapshots/integration_tests/test_get_verification_by_identity.1.json +++ b/contracts/test_snapshots/integration_tests/test_get_verification_by_identity.1.json @@ -196,6 +196,169 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "pending" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "0202020202020202020202020202020202020202020202020202020202020202" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -219,110 +382,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0101010101010101010101010101010101010101010101010101010101010101" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "pending" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "0202020202020202020202020202020202020202020202020202020202020202" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -337,7 +401,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -488,7 +552,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_get_verification_status.1.json b/contracts/test_snapshots/integration_tests/test_get_verification_status.1.json index b9ecd685..6727ad1f 100644 --- a/contracts/test_snapshots/integration_tests/test_get_verification_status.1.json +++ b/contracts/test_snapshots/integration_tests/test_get_verification_status.1.json @@ -216,6 +216,169 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "0202020202020202020202020202020202020202020202020202020202020202" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -239,110 +402,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0101010101010101010101010101010101010101010101010101010101010101" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "0202020202020202020202020202020202020202020202020202020202020202" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -357,7 +421,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -541,7 +605,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_is_verification_valid.1.json b/contracts/test_snapshots/integration_tests/test_is_verification_valid.1.json index 69c595f0..95c2de13 100644 --- a/contracts/test_snapshots/integration_tests/test_is_verification_valid.1.json +++ b/contracts/test_snapshots/integration_tests/test_is_verification_valid.1.json @@ -239,6 +239,212 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "test_reason" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -262,122 +468,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "revoked_verifications" - }, - "val": { - "vec": [ - { - "u64": 1 - } - ] - } - }, - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "test_reason" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -392,7 +487,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -609,7 +704,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_multiple_verifications_independent_revocation.1.json b/contracts/test_snapshots/integration_tests/test_multiple_verifications_independent_revocation.1.json index d26f9744..83542cf4 100644 --- a/contracts/test_snapshots/integration_tests/test_multiple_verifications_independent_revocation.1.json +++ b/contracts/test_snapshots/integration_tests/test_multiple_verifications_independent_revocation.1.json @@ -287,6 +287,330 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 2 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "reason1" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 2 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 2 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0202020202020202020202020202020202020202020202020202020202020202" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "1414141414141414141414141414141414141414141414141414141414141414" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARQG5" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -312,214 +636,15 @@ "storage": [ { "key": { - "string": "revoked_verifications" - }, - "val": { "vec": [ { - "u64": 1 + "symbol": "Counter" } ] - } - }, - { - "key": { - "string": "verification_counter" }, "val": { "u64": 2 } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0101010101010101010101010101010101010101010101010101010101010101" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "reason1" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "verification" - } - ] - }, - "val": { - "u64": 2 - } - }, - { - "key": { - "vec": [ - { - "u64": 2 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0202020202020202020202020202020202020202020202020202020202020202" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "1414141414141414141414141414141414141414141414141414141414141414" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARQG5" - } - } - ] - } } ] } @@ -528,7 +653,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -811,7 +936,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_revocation_list_maintenance.1.json b/contracts/test_snapshots/integration_tests/test_revocation_list_maintenance.1.json index a99115be..5f6104f9 100644 --- a/contracts/test_snapshots/integration_tests/test_revocation_list_maintenance.1.json +++ b/contracts/test_snapshots/integration_tests/test_revocation_list_maintenance.1.json @@ -270,6 +270,333 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 2 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "reason1" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "pending" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 2 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 2 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "0202020202020202020202020202020202020202020202020202020202020202" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "reason2" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "pending" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "1414141414141414141414141414141414141414141414141414141414141414" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + }, + { + "u64": 2 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -293,219 +620,17 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "revoked_verifications" - }, - "val": { - "vec": [ - { - "u64": 1 - }, - { - "u64": 2 - } - ] - } - }, - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 2 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0101010101010101010101010101010101010101010101010101010101010101" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "reason1" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "pending" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, "val": { "u64": 2 } - }, - { - "key": { - "vec": [ - { - "u64": 2 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "0202020202020202020202020202020202020202020202020202020202020202" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "reason2" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "pending" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "1414141414141414141414141414141414141414141414141414141414141414" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } } ] } @@ -514,7 +639,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -764,7 +889,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_revocation_status_updates.1.json b/contracts/test_snapshots/integration_tests/test_revocation_status_updates.1.json index 90ace74a..71b5c564 100644 --- a/contracts/test_snapshots/integration_tests/test_revocation_status_updates.1.json +++ b/contracts/test_snapshots/integration_tests/test_revocation_status_updates.1.json @@ -238,6 +238,212 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "security_breach" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -261,122 +467,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "revoked_verifications" - }, - "val": { - "vec": [ - { - "u64": 1 - } - ] - } - }, - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "security_breach" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -391,7 +486,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -608,7 +703,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_revoke_rejected_verification.1.json b/contracts/test_snapshots/integration_tests/test_revoke_rejected_verification.1.json index 3d6ff12c..3cdad498 100644 --- a/contracts/test_snapshots/integration_tests/test_revoke_rejected_verification.1.json +++ b/contracts/test_snapshots/integration_tests/test_revoke_rejected_verification.1.json @@ -241,6 +241,257 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "fraudulent" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "rejected" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RejectReason" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RejectReason" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "string": "invalid_proof" + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -264,137 +515,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "revoked_verifications" - }, - "val": { - "vec": [ - { - "u64": 1 - } - ] - } - }, - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "reason" - } - ] - }, - "val": { - "string": "invalid_proof" - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "fraudulent" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "rejected" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -409,7 +534,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -626,7 +751,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_revoke_verification_credential.1.json b/contracts/test_snapshots/integration_tests/test_revoke_verification_credential.1.json index 35c1aeb0..6ec91032 100644 --- a/contracts/test_snapshots/integration_tests/test_revoke_verification_credential.1.json +++ b/contracts/test_snapshots/integration_tests/test_revoke_verification_credential.1.json @@ -238,6 +238,212 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "credential_compromised" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RevokedList" + } + ] + }, + "durability": "persistent", + "val": { + "vec": [ + { + "u64": 1 + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -261,122 +467,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "revoked_verifications" - }, - "val": { - "vec": [ - { - "u64": 1 - } - ] - } - }, - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "credential_compromised" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": true - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -391,7 +486,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -608,7 +703,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_submit_and_approve_verification.1.json b/contracts/test_snapshots/integration_tests/test_submit_and_approve_verification.1.json index 201ffc62..f0e858c7 100644 --- a/contracts/test_snapshots/integration_tests/test_submit_and_approve_verification.1.json +++ b/contracts/test_snapshots/integration_tests/test_submit_and_approve_verification.1.json @@ -216,6 +216,169 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "approved" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -239,110 +402,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "approved" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -357,7 +421,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -541,7 +605,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/contracts/test_snapshots/integration_tests/test_submit_and_reject_verification.1.json b/contracts/test_snapshots/integration_tests/test_submit_and_reject_verification.1.json index 363d3c01..33ce35b7 100644 --- a/contracts/test_snapshots/integration_tests/test_submit_and_reject_verification.1.json +++ b/contracts/test_snapshots/integration_tests/test_submit_and_reject_verification.1.json @@ -218,6 +218,214 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "IdentityIndex" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u64": 1 + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Record" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "identity_id" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "proof_hash" + }, + "val": { + "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" + } + }, + { + "key": { + "symbol": "revocation_reason" + }, + "val": { + "string": "" + } + }, + { + "key": { + "symbol": "revoked" + }, + "val": { + "bool": false + } + }, + { + "key": { + "symbol": "revoked_at" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "string": "rejected" + } + }, + { + "key": { + "symbol": "verification_commitment" + }, + "val": { + "bytes": "6363636363636363636363636363636363636363636363636363636363636363" + } + }, + { + "key": { + "symbol": "verifier" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + } + ] + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RejectReason" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "RejectReason" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "string": "insufficient_proof" + } + } + }, + "ext": "v0" + }, + 535680 + ] + ], [ { "contract_data": { @@ -241,125 +449,11 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ - { - "key": { - "string": "verification_counter" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "reason" - } - ] - }, - "val": { - "string": "insufficient_proof" - } - }, - { - "key": { - "vec": [ - { - "u64": 1 - }, - { - "string": "record" - } - ] - }, - "val": { - "map": [ - { - "key": { - "symbol": "created_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "identity_id" - }, - "val": { - "u64": 1 - } - }, - { - "key": { - "symbol": "proof_hash" - }, - "val": { - "bytes": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a" - } - }, - { - "key": { - "symbol": "revocation_reason" - }, - "val": { - "string": "" - } - }, - { - "key": { - "symbol": "revoked" - }, - "val": { - "bool": false - } - }, - { - "key": { - "symbol": "revoked_at" - }, - "val": { - "u64": 0 - } - }, - { - "key": { - "symbol": "status" - }, - "val": { - "string": "rejected" - } - }, - { - "key": { - "symbol": "verification_commitment" - }, - "val": { - "bytes": "6363636363636363636363636363636363636363636363636363636363636363" - } - }, - { - "key": { - "symbol": "verifier" - }, - "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" - } - } - ] - } - }, { "key": { "vec": [ { - "u64": 1 - }, - { - "string": "verification" + "symbol": "Counter" } ] }, @@ -374,7 +468,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ], [ @@ -558,7 +652,7 @@ }, "ext": "v0" }, - 4095 + 535680 ] ] ] diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md new file mode 100644 index 00000000..8a8119ac --- /dev/null +++ b/docs/PERFORMANCE.md @@ -0,0 +1,129 @@ +# Credential Contract Performance + +Performance benchmarks for the credential (`Verification`) contract: gas/budget +cost per operation, execution time, behaviour under load, the storage bottleneck +they revealed, and the optimisation applied to fix it. + +The benchmarks live in [`contracts/src/benchmarks.rs`](../contracts/src/benchmarks.rs) +and run as ordinary `cargo test` tests, so they also act as regression guards. + +## Running the benchmarks + +```bash +cd contracts +# Run the benchmarks and print the measurement tables: +cargo test --features testutils benchmarks -- --nocapture --test-threads=1 + +# Or just run them as pass/fail regression guards (part of the normal suite): +cargo test --features testutils +``` + +## Methodology + +- **Gas / resource cost** is measured with the Soroban host budget + (`env.budget()`): `cpu_instruction_cost()` (CPU instructions) and + `memory_bytes_cost()` (memory bytes). The budget is reset before each measured + operation so costs are isolated. +- **Execution time** is wall-clock time over many iterations + (`std::time::Instant`), reported as total and per-operation. +- **Load** is measured by creating batches of credentials (N = 10, 50, 100) and + by comparing the cost of the 1st vs the 100th credential in one contract. + +### Important caveat + +These numbers are produced by the **native test host**, not by the contract +compiled to Wasm and executed on-chain. The Soroban docs note that native +execution *under-estimates* CPU and memory relative to Wasm. Additionally, the +in-memory test host re-snapshots the whole ledger on each invocation, which adds +an O(n) component to batch measurements that does **not** exist on-chain. + +Treat the figures as a **relative baseline** for comparing operations and +catching regressions — not as an exact prediction of mainnet fees. The +per-transaction network limits used as ceilings in the asserts are +`100,000,000` CPU instructions and `40 MiB` memory (Protocol 21). + +## Per-operation cost (single credential) + +Native host, isolated budget per call: + +| Operation | CPU instructions | Memory bytes | +| -------------------------- | ---------------: | -----------: | +| `submit_proof` | 84,486 | 11,981 | +| `approve_verification` | 88,094 | 11,631 | +| `reject_verification` | 124,712 | 18,526 | +| `revoke_verification` | 123,447 | 16,531 | +| `get_verification` (read) | 51,869 | 5,288 | +| `get_verification_status` | 41,463 | 4,438 | +| `is_verification_valid` | 42,654 | 4,524 | +| full lifecycle (submit→approve→revoke) | 296,023 | 40,135 | + +All operations are well within the per-transaction network limits (largest is +~0.13% of the CPU budget). + +## Behaviour under load — and the bottleneck + +The original contract stored **every per-credential record in instance +storage**. Soroban serialises the *entire* instance data set on every contract +call, so each credential operation paid to load and re-save all previously +stored credentials. The result was O(n) cost per operation and O(n²) in +aggregate. + +The load benchmark made this obvious. Creating the 100th credential cost ~51× +the 1st; a 10×-larger batch cost ~89× more: + +| Batch size | CPU (instance, before) | CPU (persistent, after) | Improvement | +| ---------: | ---------------------: | ----------------------: | ----------: | +| N=10 | 3,260,375 | 1,318,713 | 2.5× | +| N=50 | 73,943,848 | 13,605,947 | 5.4× | +| N=100 | 291,459,779 | 43,834,314 | 6.6× | + +Single-credential marginal cost (1st vs 100th in one contract): + +| Measurement | Instance (before) | Persistent (after) | +| ---------------- | ----------------: | -----------------: | +| `submit_proof` #1 | 56,729 | 84,486 | +| `submit_proof` #100 | ~2,900,000 | 766,470 | +| ratio #100 / #1 | ~51× | ~9× | + +## Optimisation applied + +Per-credential data was moved from **instance** storage to **persistent** +storage, keyed individually via a typed `DataKey` enum +(`Record(id)`, `IdentityIndex(id)`, `RejectReason(id)`, `RevokedList`). Only the +single, bounded monotonic `Counter` remains in instance storage. Persistent +entries get their TTL extended (~31 days) on read and write so active +credentials are not archived. + +Because each credential now occupies its own ledger entry, a credential +operation only touches its own data — O(1) per op on-chain instead of O(n). + +Results of the change: + +- **N=100 batch CPU: 291.5M → 43.8M (6.6× cheaper); memory 53.9M → 13.6M + (4.0× cheaper).** +- Marginal cost growth (1st → 100th credential): **~51× → ~9×** (the residual + ~9× is the test-host snapshot artifact described above; on-chain this path is + O(1)). +- Read operations also got cheaper because reads no longer deserialise the whole + instance map: `get_verification` −26%, `is_verification_valid` −30%. +- Trade-off: a single isolated `submit_proof` is slightly more expensive + (56.7k → 84.5k CPU) due to the per-entry TTL extension, but this fixed cost is + dwarfed by the scaling win at any realistic credential volume, and + `approve`/`reject` got cheaper. + +## Remaining considerations / future work + +- **`revoked_verifications` list:** `revoke_verification` still appends to a + single `Vec` that is read and rewritten in full on each call — O(n) in the + number of revocations. It now lives in persistent storage (so it no longer + bloats every other operation), and revocation status is also stored directly on + each record (`record.revoked`), so the list is only needed for enumeration via + `get_revoked_verifications`. For high revocation volumes, consider replacing the + monolithic list with paginated keys or relying on the emitted + `VerificationRevoked` events for off-chain indexing. +- **`is_verification_valid`** allocates a `String` (`"approved"`) per call for + comparison. Negligible today; could use an integer/enum status if status ever + becomes hot-path. +- **On-chain measurement:** for fee-accurate numbers, re-run these scenarios + against the Wasm build via the Stellar CLI / RPC `simulateTransaction` and + record the resource fees. The relative ordering here should hold.