Repository navigation
Performance Optimization
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document provides advanced performance optimization guidance for Sigvara across its smart contracts, oracle service, monitoring, and operational workflows. It focuses on:
- Gas optimization techniques for upgradeable contracts, including storage layout, function call patterns, and proposal/finalization flows.
- Oracle service tuning, including caching, database-like persistence, concurrent RPC handling, and epoch scheduling.
- Monitoring and metrics collection to detect bottlenecks, regressions, and capacity limits.
- Profiling, benchmarking, and load testing strategies grounded in the repository’s existing test suites and runtime behavior.
- Scalability considerations for high-throughput scenarios, memory management, and resource allocation across distributed components.
The guidance is derived from the current codebase and deployment model, which uses UUPS upgradeable proxies, an optimistic reputation update flow, a bonded oracle operator with a checker mode, and Prometheus-style in-memory metrics.
At a high level, Sigvara consists of:
- On-chain registry and reputation contracts under
src/. - An off-chain Node.js oracle service under
oracle/that computes scores, scans chain events, proposes and finalizes updates, and exposes HTTP endpoints. - A TypeScript SDK under
packages/sdk/used by consumers and operators. - Foundry-based contract tests and JavaScript tests for the oracle.
- Documentation describing protocol architecture, token policy, and deployment status.
graph TB
subgraph "On-chain"
ID["SigvaraIdentity<br/>agent registry"]
REP["SigvaraReputation<br/>score anchor"]
STK["SigvaraStaking<br/>bond + slash"]
ORB["SigvaraOracleBond<br/>operator bond"]
end
subgraph "Off-chain"
ORC["Oracle Service<br/>epoch loop, scoring, RPC"]
MET["Metrics Exporter<br/>Prometheus text"]
SDK["SDK Consumers<br/>threshold checks"]
end
ORC --> REP
ORC --> ID
ORC --> MET
SDK --> REP
STK --> REP
ORB --> REP
Diagram sources
Section sources
The performance-critical components are:
-
SigvaraIdentity: agent identity, operator index, status transitions, and transfer mechanics. -
SigvaraReputation: optimistic score proposals, challenge windows, maturity, evidence roots, and threshold reads. - Oracle service: epoch orchestration, payment scanning, concurrent RPC batching, caching, and metrics.
Key performance characteristics visible in the code:
- Contracts use UUPS upgradeable proxies and append-only storage layout changes to avoid rewrites during upgrades.
- Reputation updates are optimistic: propose, challenge window, then finalize.
- The oracle batches independent reads, chunks large workloads, and separates read-heavy phases from write-heavy phases.
- Metrics are in-process counters exposed as Prometheus text.
Section sources
Sigvara’s trust layer sits above ERC-8004 identity and feedback. The oracle consumes signals such as payment-backed attestations, watchdog flags, external feedback, and counterparty standing, then proposes normalized scores. Slashing can zero a score, and consumers gate actions on meetsThreshold.
sequenceDiagram
participant Source as "Signal Sources"
participant Oracle as "Oracle Service"
participant Identity as "SigvaraIdentity"
participant Reputation as "SigvaraReputation"
participant Staking as "SigvaraStaking"
participant Consumer as "Consumer / SDK"
Source->>Oracle : Attestations, flags, payments
Oracle->>Identity : Read agent info
Oracle->>Oracle : Compute factors and Merkle root
Oracle->>Reputation : proposeReputation()
Reputation-->>Oracle : ScoreProposed event
Note over Reputation : Challenge window open
Consumer->>Reputation : meetsThreshold()
alt Committee rejects
Staking->>Reputation : rejectReputation()
else Window elapses
Oracle->>Reputation : finalizeReputation()
Reputation-->>Consumer : Live score
end
Staking->>Reputation : zeroReputation() on slash
Diagram sources
Section sources
- Both
SigvaraIdentityandSigvaraReputationuse OpenZeppelin UUPS upgradeable proxies. - New state variables are appended after existing ones so upgrades do not shift base slots. This avoids expensive storage migration and keeps proxy compatibility predictable.
- In
SigvaraIdentity, fields likeslashSuspended,stakeView,pendingOperator,operatorChangedAt,operatorTransferCount, andoperatorAgentIndexare appended deliberately. - In
SigvaraReputation, fields likeidentityRegistry,maturityRatePerDay,maturedScore,maturedAt,operatorBond, andevidenceRootsare appended.
Optimization implications:
- Append-only layout reduces upgrade risk and keeps gas costs stable across versions.
- Avoid inserting new mappings before live mappings; otherwise, slot shifts can silently change semantics or break access control.
- On
main,PendingScoregainedproposerandfinalizableAtat the end of its struct, and the inflow pause (InflowGuard) keeps its state in an ERC-7201 namespaced slot, so adding either to a live proxy shifts no existing variable.
Section sources
-
SigvaraReputation.proposeIfEmptyprevents overwriting a pending proposal. This is important for the checker operator because overwriting would restart the challenge window and destroy divergence evidence. Onmainit does replace a pending proposal whose proposer has lost its authority, since that one can never be finalized. -
finalizeReputationperforms permissionless finalization after the challenge window, reducing dependency on any single party’s liveness. Onmainthe end of the window is fixed when the proposal is made (finalizableAt, a contract-side value; the oracle decides fromproposedAtplus the live window), and finalizing also asks whether the proposer could still make the proposal. -
getTotalScoredoes read-time maturity extrapolation rather than storing matured values per block, saving storage writes while still exposing spendable scores.
Gas-saving patterns:
- Early guards skip expensive computation when a proposal is already pending or an agent is slashed/unbonded.
- View functions compute totals without extra storage writes.
- Evidence verification uses Merkle proofs instead of full data inclusion.
Section sources
- SigvaraReputation.sol:386-448
- SigvaraReputation.sol:450-504
- SigvaraReputation.sol:696-752
- SigvaraReputation.sol:761-769
-
SigvaraIdentitymaintains an operator-to-agents list and a position map to support constant-time removal via swap-and-pop. - This avoids linear scans on the transfer path, preventing self-inflicted DoS where an operator registers many agents and blocks their own transfers due to gas exhaustion.
Optimization implications:
- Transfer operations become more predictable and less likely to hit block gas limits.
- Paging helpers exist for callers who cannot afford unbounded lists.
Section sources
- Initialization methods are versioned (
initializeV2,initializeV3,initializeV4) so live proxies consume only the needed upgrade logic. - Fail-closed wiring ensures missing configuration (e.g., identity registry, stake view) causes safe reverts rather than silent misconfiguration.
- Admin setters allow post-deployment wiring without requiring full redeployments. On
mainthe wiring setters (setStakeView,setOperatorBond,setSlashBeneficiary) needUPGRADER_ROLE, so they go through the timelock, and the setters for the periods, the score window and the maturity rate have floors and ceilings.
Operational performance benefits:
- Upgrades are targeted and auditable.
- Misconfiguration is caught early.
- Governance can tune parameters like maturity rate and challenge window without changing implementation code.
Section sources
- The oracle runs epochs with a guard against overlapping executions to prevent nonce collisions from shared wallet usage.
- Phase 1 performs stateless reads concurrently but in chunks to avoid overwhelming RPC providers.
- Phase 2 handles writes sequentially because they share the oracle wallet nonce, but it batches guard reads ahead in chunks to reduce round trips.
Tuning recommendations:
- Keep
LOG_CHUNK_SIZEandPAYMENT_SCAN_CHUNKaligned with provider batch limits and rate limits; the epoch's own read chunks are fixed at 32. - Monitor
epochsStarted,epochsSucceeded, andepochsFailedto detect epoch stalls. - Ensure the checker’s epoch interval is comfortably shorter than half the challenge window.
- Each transaction is waited for a bounded time (
TX_WAIT_SECONDS, then one replacement at the same nonce and twice the fee), so a dropped transaction cannot hold an epoch, and every later tick, for ever.
Section sources
- The oracle can scan chain
Transferlogs for registered agent addresses, crediting payments even if no attestation was submitted. - A canary check validates that the scan query itself works when no payments are found, distinguishing “no activity” from “broken query.”
- Checkpoints ensure partial scans resume safely without losing unresolved blocks.
Tuning recommendations:
- Enable payment scanning when evidence consistency between operators matters.
- Watch
paymentScans,paymentsPulled,paymentScanErrors, andpaymentScanCanaryFailures. - Tune
chunkSize,paceMs, and confirmation depth based on RPC provider capabilities. - The Arc testnet endpoints limit with a bucket of about 60 requests. Measured on 3 October 2026, back-to-back
getLogscalls were refused about 60% of the time, 250 ms between calls failed every call after the first 60, and the default 500 ms sustained 72 of 72. Do not lowerLOG_CHUNK_SIZEto ease throttling: the limit is on request rate, so a smaller chunk means more calls. A mainnet note inoracle/.env.mainnet.checker.examplerecords QuickNode refusing 16 of 60 calls at two a second.
Section sources
- Payer standing cache avoids repeated RPC calls for the same counterparty within an epoch.
- Response caching is available through
response-cache.js, and badge metrics expose cache hits versus RPC errors. - Evidence responses can be cached to reduce recomputation and RPC pressure.
- Stored payment events are frozen, and
merkle.jscaches each leaf and each agent's root by identity. An epoch in which an agent's evidence has not changed reuses its root instead of hashing every payment again.
Tuning recommendations:
- Use payer standing cache for propagation calculations.
- Monitor badge cache hit ratio; falling ratios indicate increased RPC load.
- The evidence response cache is fixed at 32 MiB and the badge cache at 500 entries for 60 seconds; watch memory against the container limit.
Section sources
- The oracle persists attestations, flags, links, scan state, payment events, cooldowns, and divergences through
store.js. - State is loaded at startup and persisted after successful operations, ensuring resilience across restarts.
- The file is written in pieces of about 1 MB rather than as one string, and the file each save replaces is kept as
<state>.bak. Measured on Node 20, the peak memory of one save fell from 449 MB to 189 MB with 100,000 payments and from 700 MB to 280 MB with 200,000; save time is unchanged at 100,000 payments and 12 to 26 percent lower beyond that.
Tuning recommendations:
- Mount persistent volumes for state durability.
- Size the container for the peak of a save, not the size of the file (the mainnet compose file limits it to 768 MB).
- Prune expired cooldowns and old divergences to bound memory growth.
- Back up state files alongside chain indices to enable recovery.
Section sources
- Independent RPC reads are issued concurrently using
Promise.all, but grouped into chunks to respect provider limits. - Payer score lookups deduplicate addresses and batch misses together.
- Guard reads for multiple candidates are batched to minimize sequential latency.
Tuning recommendations:
- Profile RPC latency and adjust
LOG_CHUNK_SIZE,PAYMENT_SCAN_CHUNKand the scan pace. - Use separate RPC providers for primary, checker, and watcher roles to reduce contention.
- Track
httpRequests,rateLimitHits, and provider-specific throttling metrics.
Section sources
The oracle exports Prometheus-style metrics covering:
- Epoch lifecycle: started, succeeded, failed.
- Proposal and finalization attempts and outcomes.
- Fee charges (taken, skipped, already paid) and errors.
- Attestation acceptance and rejection reasons.
- Payment verification and RPC errors.
- Checker comparisons: diverged vs agreed.
- Badge requests, cache hits, and RPC errors.
- ERC-8183 job reads and errors.
- Payment scan counts, pulled payments, errors, canary failures, and refused credits.
- Provider throttling and rate limit hits.
- Transactions refused for their fee, or sent and never seen mined.
- HTTP request volume.
- Process uptime, last successful epoch timestamp, and active agents.
Operational guidance:
- Alert on
epochsFailed,paymentScanErrors,paymentScanCanaryFailures,txCapped,txUnconfirmed, and risingproposeThrottled/finalizeThrottled. - Track
checkerDivergencesto detect scoring disagreements. - Monitor badge cache hit ratio to detect cache inefficiency.
- Use
activeAgentsgauge to understand workload scaling.
Section sources
Common bottlenecks visible in the code:
- RPC rate limiting during bulk reads or writes.
- Long epoch durations caused by sequential waits.
- Evidence cache misses increasing RPC load.
- Payment scan queries failing or being pruned by provider node history policies.
- Large operator agent lists causing paging overhead.
Detection strategies:
- Compare
epochsStartedvsepochsSucceededover time. - Correlate
rateLimitHitswith proposal/finalization success rates. - Inspect
paymentScanRefusedfor state inconsistencies. - Review
badgeCacheHitsvsbadgeRequestsfor cache effectiveness.
Section sources
- Contract tests include unit, fuzz, E2E, upgrade, deploy-script, handover, and invariant suites (693 tests as of 27 October 2026).
- Oracle tests (760) cover adversarial scenarios, badges, chain interactions and chain safety (fee caps, transaction replacement, wrong chain), epoch policy, external feeds, HTTP helpers, jobs, merkle proofs, metrics, payments, payments scanning, scoring, startup settings and the signing key, store behavior and the streamed state file, policy watchers, and end-to-end runs of the real
index.jsandwatcher.jsagainst a stubbed chain. - SDK tests cover agent, challenge, DID, gate, keys, stake, verifier, and integration paths.
Benchmarking guidance:
- Use Foundry fuzz profiles to stress edge cases and gas-sensitive paths.
- Use the harnesses in
scripts/mutationto measure whether the contract and deploy-script tests would catch a deliberate break. - Run oracle tests to validate scoring determinism and error handling.
- Use integration tests to exercise full lifecycle: registration, staking, reputation proposal/finalization, slashing, and dispute resolution.
Load testing guidance:
- Simulate high-throughput attestation ingestion and payment scanning.
- Generate many operator-agent relationships to test paging and index removal.
- Stress RPC providers with controlled bursts to validate chunking and backoff behavior.
Section sources
- Chunked concurrent reads prevent RPC saturation.
- Sequential writes protect nonce ordering while minimizing redundant checks.
- Checker mode adds auditability without competing for the same proposal slot.
Recommendations:
- Scale horizontally by running independent operators with separate RPC providers. A second operator runs as a checker, not as a second proposer.
-
PHASE_ONE_CHUNKandGUARD_CHUNKare constants (32 each) inrunEpochInner, not settings; the settings that change provider load areLOG_CHUNK_SIZE,PAYMENT_SCAN_CHUNKandPAYMENT_SCAN_PACE_MS. - Ensure the checker epoch cadence is shorter than half the challenge window.
Section sources
- In-memory caches for payer standings and response data must be sized appropriately.
- Persistent state should be pruned periodically to avoid unbounded growth.
- A save of the state file peaks at the live state plus one piece of about 1 MB (395 MB at 400,000 payments, against 1,628 MB before the file was streamed).
- Evidence cache size and byte usage are exposed via metrics.
Recommendations:
- Monitor evidence cache entries and bytes.
- Implement eviction policies for stale evidence and divergences.
- Separate process memory for heavy computations from long-lived state stores.
Section sources
- Primary oracle, checker, and watcher run on separate hosts and RPC providers.
- The watcher observes disagreement without holding keys, reducing risk exposure.
- Separation ensures one failure does not silence both auditing and alerting.
Recommendations:
- Deploy each role on isolated infrastructure.
- Use distinct RPC providers to avoid shared rate limits.
- Monitor divergence exposure and escalation paths.
Section sources
graph LR
ID["SigvaraIdentity.sol"] --> STK["SigvaraStaking.sol"]
REP["SigvaraReputation.sol"] --> ID
REP --> ORB["SigvaraOracleBond.sol"]
ORC["oracle/index.js"] --> CHAIN["chain.js"]
ORC --> EXTERNAL["external.js"]
ORC --> PAYMENTS["payments.js"]
ORC --> SCORING["scoring.js"]
ORC --> STORE["store.js"]
ORC --> METRICS["metrics.js"]
Diagram sources
Section sources
- Prefer view functions for reads to avoid transaction costs.
- Batch independent reads and chunk large workloads.
- Use Merkle proofs for evidence verification instead of full data inclusion.
- Maintain append-only storage layouts for upgrade safety.
- Avoid unbounded loops in hot paths; provide paging APIs.
- Use chain clock for deterministic scoring and decay calculations.
- Deduplicate and batch RPC calls.
- Cache frequently accessed data within epochs.
- Separate read and write phases to reduce contention.
- Monitor and tune chunk sizes, pacing, and confirmation depths.
- Track epoch success rates and proposal/finalization outcomes.
- Alert on provider throttling and rate limit hits.
- Watch checker divergence counts and badge cache hit ratios.
- Validate payment scan canary results to detect broken queries.
- Run Foundry fuzz and invariant tests to find gas and logic regressions.
- Use oracle tests to validate scoring determinism and error handling.
- Simulate high-throughput scenarios to validate concurrency and caching.
- Scale operators horizontally with independent RPC providers.
- Bound memory usage with cache eviction and state pruning.
- Isolate roles to prevent shared failure modes.
- Epoch skipped due to overlapping execution: check
epochRunningguard and nonce collisions. - RPC throttling: monitor
proposeThrottled,finalizeThrottled, andrateLimitHits; adjust pacing and chunk sizes. - Payment scan query broken: watch
paymentScanCanaryFailures; verify provider node history retention. - Divergence between operators: inspect
checkerDivergencesand compare evidence roots.
Section sources
- Missing identity registry or stake view: initialization must complete before proposals or status changes.
- Agent slashed or unbonded: proposals revert; ensure agent is Active and bonded.
- Pending proposal race: use
proposeIfEmptyfor checker mode to avoid overwriting.
Section sources
Sigvara’s performance hinges on careful gas-aware contract design, deterministic and concurrent oracle processing, robust caching, and comprehensive metrics. By maintaining append-only storage layouts, batching RPC calls, enforcing optimistic proposal flows, and monitoring key counters, operators can optimize throughput, reduce latency, and detect regressions early. For high-throughput deployments, horizontal scaling, isolated roles, and bounded memory usage are essential. The existing test suites and metrics provide a strong foundation for profiling, benchmarking, and load testing across all layers.
- Oracle environment variables include RPC URL, private key (or key file), identity and reputation addresses, expected chain id, epoch interval, host/port, trusted proxies, log chunk size, admin tokens, fee registry address, external RPC and registry addresses, checker mode, divergence tolerance, primary evidence URL, transaction wait and fee caps, and the clock-skew limit.
- Payment scanning configuration includes asset, confirmations, chunk size, pace, and from block.
Section sources
- Agent Registration and Lifecycle
- Contract Overview and Architecture
- Economic Security Model and Incentives
- Evidence Verification and Merkle Proofs
- Key Management and Rotation
- Maturity Mechanism and Score Release
- Proposal Workflow and Challenge System
- Score Storage and Data Model
- SigvaraIdentity Contract
- SigvaraOracleBond Contract
- SigvaraReputation Contract
- SigvaraStaking Contract
- Slashing Lifecycle and Dispute Resolution
- Stake Management Functions
- Status Management and Control
- Token and Fee Contracts
- Unbonding Period and Withdrawal Security
- Anti-Manipulation and Security Measures
- Community Flag Processing
- Evidence Sources and Verification
- External Trust Integration
- Merkle Proof System
- Oracle Score Computation
- Payment-Backed Attestations
- Scoring Model and Formulas
- Agent Creation and Key Management
- Agent Operations
- Agent Registration Workflow
- Challenge-Response Authentication
- Gate Access Control
- Integration Patterns and Examples
- SDK Overview and Setup
- Verifier Functions