Standard operating procedures for daily operations, incident response, and escalation paths for QuorumProof platform operators.
- Daily Operations
- Monitoring & Alerting
- Incident Response
- Escalation Procedures
- Maintenance Windows
- Disaster Recovery
- Contact Information
Time: Start of each shift (every 8 hours)
Checklist:
- Check monitoring dashboard for alerts
- Review contract event logs from past 8 hours
- Verify all contract instances are responding
- Check RPC endpoint health
- Review dispute queue for pending resolutions
- Verify admin key accessibility (hardware wallet connected)
- Check IPFS pinning service status
- Review credential issuance volume (compare to baseline)
Tools:
- Grafana dashboard:
https://monitoring.quorumproof.io/grafana - Soroban RPC:
https://soroban-testnet.stellar.org(testnet) orhttps://soroban-mainnet.stellar.org(mainnet) - IPFS status:
ipfs daemon --statsor Pinata dashboard
Expected Baseline:
- Credential issuance: 10-50 per day (testnet), 100-500 per day (mainnet)
- Dispute filings: 0-5 per day
- Failed transactions: < 1% of total
Action if Baseline Exceeded:
- Investigate unusual activity (see Section 3: Incident Response)
- Check for DDoS or spam attacks
- Review recent contract changes
Time: Every hour, automated
Checks:
# Check contract responsiveness
stellar contract invoke \
--network testnet \
--contract $CONTRACT_QUORUM_PROOF \
-- get_credential_count
# Check RPC latency
time curl -X POST https://soroban-testnet.stellar.org \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getLatestLedger","params":[]}'
# Check IPFS connectivity
ipfs swarm peers | wc -l
# Check contract pause status
stellar contract invoke \
--network testnet \
--contract $CONTRACT_QUORUM_PROOF \
-- is_pausedExpected Results:
get_credential_count: Returns u64 (no error)- RPC latency: < 500ms
- IPFS peers: > 10
is_paused: false
Action if Check Fails:
- See Section 3: Incident Response
Time: Once per day (recommended: 00:00 UTC)
Procedure:
- Export credential count:
get_credential_count() - Export slice count:
get_slice_count() - Export revocation count:
get_revoked_count() - Compare to previous day
- Flag unusual changes (> 50% increase/decrease)
Script:
#!/bin/bash
DATE=$(date +%Y-%m-%d)
CRED_COUNT=$(stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_credential_count)
SLICE_COUNT=$(stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_slice_count)
REVOKED_COUNT=$(stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_revoked_count)
echo "$DATE,credentials=$CRED_COUNT,slices=$SLICE_COUNT,revoked=$REVOKED_COUNT" >> audit.logRetention: Keep audit logs for 2 years
Time: Twice per day (08:00 UTC, 16:00 UTC)
Procedure:
- Query pending disputes:
get_pending_disputes() - For each dispute:
- Check filing timestamp
- Verify evidence hash is accessible on IPFS
- Notify slice members if > 24 hours old
- Escalate if > 7 days old (see Section 4: Escalation)
Script:
#!/bin/bash
DISPUTES=$(stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_pending_disputes)
for DISPUTE_ID in $DISPUTES; do
DISPUTE=$(stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_dispute $DISPUTE_ID)
FILED_AT=$(echo $DISPUTE | jq .filed_at)
EVIDENCE_HASH=$(echo $DISPUTE | jq .evidence_hash)
# Check if evidence is available on IPFS
ipfs cat $EVIDENCE_HASH > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "WARNING: Evidence unavailable for dispute $DISPUTE_ID"
fi
# Check age
AGE_HOURS=$(( ($(date +%s) - $FILED_AT) / 3600 ))
if [ $AGE_HOURS -gt 24 ]; then
echo "ALERT: Dispute $DISPUTE_ID pending for $AGE_HOURS hours"
fi
doneFrequency: Quarterly (every 90 days)
Keys to Rotate:
- Admin Stellar account (if single-sig; multi-sig rotates individual signers)
- Issuer accounts (if managed by operator)
- ZK prover private key (annually)
Procedure:
- Generate new key
- Test new key with testnet deployment
- Schedule rotation window (low-traffic period)
- Update key in hardware wallet
- Document old key in secure archive
- Verify new key works with all operations
Backup:
- Store encrypted backup in secure vault
- Maintain geographically distributed copies
- Test recovery procedure quarterly
| Metric | Threshold | Severity | Action |
|---|---|---|---|
| RPC Latency | > 1000ms | High | Check RPC endpoint, consider failover |
| Contract Error Rate | > 5% | High | Investigate error logs |
| Credential Issuance Rate | > 2x baseline | Medium | Check for spam, investigate source |
| Dispute Filing Rate | > 10/day | Medium | Monitor for abuse |
| IPFS Availability | < 80% | High | Check pinning service, add replicas |
| TTL Expiry Events | > 0 | Critical | Immediate investigation (data loss) |
| Pause Events | Any | High | Verify admin action, check logs |
| Unauthorized Auth Attempts | > 0 | Critical | Investigate potential attack |
Grafana Alerts:
- alert: HighRPCLatency
expr: rpc_latency_ms > 1000
for: 5m
annotations:
summary: "RPC latency high: {{ $value }}ms"
action: "Check RPC endpoint health"
- alert: HighContractErrorRate
expr: rate(contract_errors[5m]) > 0.05
for: 5m
annotations:
summary: "Contract error rate: {{ $value }}"
action: "Review contract logs"
- alert: UnusualCredentialVolume
expr: rate(credentials_issued[1h]) > 2 * avg_over_time(credentials_issued[24h])
for: 10m
annotations:
summary: "Credential issuance spike"
action: "Investigate source, check for spam"
- alert: TTLExpiryDetected
expr: ttl_expiry_events > 0
for: 1m
annotations:
summary: "TTL expiry detected (data loss)"
action: "CRITICAL: Immediate investigation required"Logs to Collect:
- Contract event logs (Soroban RPC)
- RPC endpoint logs
- IPFS daemon logs
- Application logs (API server, dashboard)
- Admin action logs
Retention: 90 days (hot), 2 years (archive)
Tools: ELK Stack, Datadog, or CloudWatch
| Severity | Response Time | Escalation | Example |
|---|---|---|---|
| Critical | Immediate (< 5 min) | Level 2 | Data loss, unauthorized access, contract exploit |
| High | 15 minutes | Level 1 | Service degradation, high error rate, DDoS |
| Medium | 1 hour | Level 1 | Unusual activity, performance degradation |
| Low | 4 hours | None | Minor bugs, documentation issues |
Scenario: TTL Expiry Detected (Data Loss)
Steps:
-
Immediate (< 1 min):
- Pause contract:
pause() - Alert Level 2 on-call engineer
- Notify stakeholders
- Pause contract:
-
Investigation (1-5 min):
- Identify affected credentials
- Check TTL extension logs
- Determine root cause (code bug, missed extension, etc.)
-
Remediation (5-30 min):
- If code bug: Deploy fix
- If missed extension: Manually extend TTL
- Restore from backup if necessary
-
Verification (30-60 min):
- Verify affected credentials are recoverable
- Test contract operations
- Unpause contract
-
Post-Incident (1-24 hours):
- Root cause analysis
- Implement preventive measures
- Update runbook
Escalation: Immediately to Level 2 (Security Lead)
Scenario: Unauthorized Credential Issuance
Steps:
-
Immediate (< 1 min):
- Pause contract
- Alert Level 2 on-call engineer
- Preserve transaction logs
-
Investigation (1-10 min):
- Identify unauthorized issuer
- Check if issuer key was compromised
- Determine scope (how many credentials issued)
-
Remediation (10-30 min):
- Revoke unauthorized credentials
- Rotate compromised key
- Deploy contract fix if vulnerability found
-
Verification (30-60 min):
- Verify revocations are effective
- Test contract with new key
- Unpause contract
-
Post-Incident (1-24 hours):
- Security audit
- Notify affected parties
- Update security procedures
Escalation: Immediately to Level 2 (Security Lead) and Level 3 (CISO)
Scenario: High Error Rate (> 5%)
Steps:
-
Immediate (< 5 min):
- Check RPC endpoint health
- Review error logs
- Check contract state
-
Investigation (5-15 min):
- Identify error type (contract error, RPC error, network error)
- Check for recent deployments
- Check for DDoS or spam
-
Remediation (15-60 min):
- If RPC issue: Failover to backup RPC
- If contract issue: Pause and investigate
- If DDoS: Enable rate limiting
-
Verification (60-120 min):
- Monitor error rate
- Verify normal operation
- Document root cause
Escalation: To Level 1 (On-call Engineer) if not resolved in 15 minutes
Scenario: Service Degradation (RPC Latency > 1000ms)
Steps:
-
Immediate (< 5 min):
- Check RPC endpoint status
- Check network connectivity
- Review recent changes
-
Investigation (5-15 min):
- Check RPC logs for errors
- Monitor latency trend
- Check for DDoS
-
Remediation (15-60 min):
- If RPC overloaded: Failover to backup RPC
- If network issue: Contact ISP
- If DDoS: Enable rate limiting
-
Verification (60-120 min):
- Monitor latency
- Verify normal operation
Escalation: To Level 1 (On-call Engineer) if not resolved in 15 minutes
INCIDENT REPORT
===============
ID: INC-2026-05-29-001
Severity: [Critical/High/Medium/Low]
Status: [Open/Resolved/Closed]
Timeline:
- 2026-05-29 14:30 UTC: Alert triggered
- 2026-05-29 14:32 UTC: On-call engineer notified
- 2026-05-29 14:35 UTC: Investigation started
- 2026-05-29 14:45 UTC: Root cause identified
- 2026-05-29 15:00 UTC: Fix deployed
- 2026-05-29 15:15 UTC: Verified resolved
Root Cause:
[Description of root cause]
Impact:
- Affected users: [number]
- Affected credentials: [number]
- Duration: [time]
Resolution:
[Description of fix]
Prevention:
[Steps to prevent recurrence]
Lessons Learned:
[What we learned]
Owner: [Name]
Reviewer: [Name]
Level 0: Automated monitoring and alerting
- No human intervention required
- Automatic remediation (e.g., failover)
Level 1: On-call Engineer
- Response time: 15 minutes
- Authority: Investigate, implement fixes, pause contract
- Cannot: Deploy to mainnet, rotate admin keys
Level 2: Security Lead
- Response time: 30 minutes
- Authority: All Level 1 + security decisions, key rotation
- Cannot: Override business decisions
Level 3: CISO / Executive
- Response time: 1 hour
- Authority: All Level 2 + business decisions, public communication
- Cannot: Technical decisions (deferred to Level 2)
| Condition | Escalate To | Reason |
|---|---|---|
| Incident not resolved in 15 min | Level 1 | Requires human intervention |
| Security incident | Level 2 | Requires security expertise |
| Data loss or corruption | Level 2 | Requires security review |
| Mainnet impact | Level 3 | Requires executive approval |
| Public communication needed | Level 3 | Requires executive decision |
| Regulatory notification required | Level 3 | Requires legal review |
See Section 7: Contact Information
Frequency: Monthly (first Sunday of each month)
Duration: 2 hours (02:00-04:00 UTC)
Activities:
- Contract upgrades
- Dependency updates
- Database maintenance
- Security patches
Notification:
- Announce 2 weeks in advance
- Send reminder 24 hours before
- Post status updates during maintenance
Before Maintenance:
- Backup contract state
- Backup database
- Notify stakeholders
- Prepare rollback plan
- Test changes on testnet
During Maintenance:
- Pause contract
- Deploy changes
- Run smoke tests
- Monitor for errors
- Unpause contract
After Maintenance:
- Verify all operations
- Check monitoring dashboard
- Document changes
- Send completion notification
Trigger: Critical security vulnerability or data loss
Procedure:
- Pause contract immediately
- Assess impact
- Develop fix
- Deploy fix to testnet
- Test thoroughly
- Deploy to mainnet
- Unpause contract
- Notify stakeholders
No advance notice required (security incident)
What to Backup:
- Contract state (ledger entries)
- Database (credentials, slices, disputes)
- Configuration files
- Admin keys (encrypted)
Backup Frequency:
- Contract state: Continuous (Stellar ledger)
- Database: Daily (incremental), Weekly (full)
- Configuration: On change
- Keys: On rotation
Backup Location:
- Primary: Secure vault (on-premises)
- Secondary: Cloud storage (encrypted)
- Tertiary: Geographically distributed (different region)
Scenario: Database Corruption
Steps:
- Pause contract
- Restore database from latest backup
- Verify data integrity
- Replay transactions from contract logs
- Unpause contract
RTO: 1 hour RPO: 1 day
Scenario: Contract State Loss
Steps:
- Pause contract
- Redeploy contract from source
- Restore state from backup
- Verify state matches ledger
- Unpause contract
RTO: 2 hours RPO: Continuous (Stellar ledger is immutable)
Scenario: Admin Key Compromise
Steps:
- Pause contract immediately
- Rotate admin key
- Audit all admin actions since compromise
- Revoke any unauthorized changes
- Unpause contract
RTO: 30 minutes RPO: Depends on detection time
Frequency: Quarterly
Test Scenarios:
- Database restore from backup
- Contract state recovery
- Admin key rotation
- RPC failover
- IPFS pinning service failover
Documentation: Record test results and any issues found
| Role | Name | Phone | Backup | |
|---|---|---|---|---|
| On-Call Engineer | [Name] | [Phone] | [Email] | [Backup Name] |
| Security Lead | [Name] | [Phone] | [Email] | [Backup Name] |
| CISO | [Name] | [Phone] | [Email] | [Backup Name] |
On-Call Schedule: [Link to calendar]
Level 1 (On-Call Engineer):
- Phone: [Number]
- Slack: #incidents
- Email: oncall@quorumproof.io
Level 2 (Security Lead):
- Phone: [Number]
- Slack: @security-lead
- Email: security@quorumproof.io
Level 3 (CISO):
- Phone: [Number]
- Slack: @ciso
- Email: ciso@quorumproof.io
Stellar Support:
- Email: support@stellar.org
- Slack: [Stellar Dev Slack]
IPFS Support:
- Email: support@protocol.ai
- Slack: [IPFS Community Slack]
Cloud Provider (if applicable):
- Support Portal: [URL]
- Phone: [Number]
# Get credential count
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_credential_count
# Get credential details
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_credential 1
# Check if paused
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- is_paused
# Get pending disputes
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_pending_disputes
# Get slice details
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_slice 1# Pause contract
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF \
--source-account $ADMIN_KEY -- pause
# Unpause contract
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF \
--source-account $ADMIN_KEY -- unpause
# Revoke credential
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF \
--source-account $ISSUER_KEY -- revoke_credential $CREDENTIAL_ID# Check RPC health
curl -X POST https://soroban-testnet.stellar.org \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getLatestLedger","params":[]}'
# Check IPFS connectivity
ipfs swarm peers
# Monitor contract events
stellar contract invoke --network testnet --contract $CONTRACT_QUORUM_PROOF -- get_events
# Check transaction status
stellar transaction info $TX_HASH| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-05-29 | [Author] | Initial version |
Last Updated: May 29, 2026 Next Review: November 29, 2026
Meaning: The quorumproof_ws_messages_dropped_total counter is growing faster than 0.1 drops/s sustained for 2+ minutes. This means one or more WebSocket clients are consuming messages slower than the server is producing them, causing the per-connection send queue (api-server/src/ws/connectionQueue.ts) to overflow and drop the oldest queued messages. A push-based alert is also dispatched via alertChannels.ts when the in-process drop window counter reaches WS_DROP_ALERT_THRESHOLD (default: 10) within a WS_DROP_ALERT_WINDOW_SECONDS (default: 60s) window.
Impact: Affected clients will miss real-time events. They should reconcile on reconnect via REST (see useRealtimeUpdates.ts which performs a full fetch on reconnect).
Recommended operator response:
- Identify the affected instance: check
quorumproof_ws_connections{instance=...}andquorumproof_ws_messages_dropped_total{instance=...}to pinpoint which replica is dropping. - Inspect client connectivity: are specific clients on slow networks, in tight receive loops, or experiencing high CPU load on their side?
- If drops are concentrated on one client, consider terminating that WebSocket connection (the client will reconnect and reconcile via REST).
- If drops are systemic across many connections, check server CPU and memory — an overloaded server may be unable to drain queues fast enough.
- Tune queue limits for bursty workloads: increase
WS_SEND_QUEUE_MAX_MESSAGES(default: 200) and/orWS_SEND_QUEUE_MAX_BYTES(default: 1 MiB) at the cost of higher memory usage per connection. - Tune alert sensitivity via
WS_DROP_ALERT_THRESHOLD(drops per window before alerting) andWS_DROP_ALERT_WINDOW_SECONDS(observation window length).