Hands-On DevOps Engineering

Hands-On DevOps Engineering

The Autonomous Platform Architect: 2026 Edition — Building Self-Healing, AI-Native Systems

Day 61: Anonymous Polling — Voting with ZK-SNARKs

NexusCore: The Autonomous Platform Architect, 2026 Edition

Devops's avatar
Devops
Sep 30, 2026
∙ Paid

The Abstraction Trap

Here’s how a junior engineer ships “anonymous voting” in 2026: pull in a Node.js wrapper around snarkjs, spin up a verifier microservice per proof request (often literally docker run or a forked Python py_ecc process because “the crypto library needs its own runtime”), and enforce one-vote-per-person with a Postgres UNIQUE(nullifier_hash) constraint on the votes table. It demos beautifully at 50 concurrent users in a conference talk.

The abstraction hides three things simultaneously: (1) the cost of proof verification is being paid as a cold-start penalty, not an execution cost, (2) uniqueness enforcement has been handed to a single relational index instead of being pushed to the layer that’s actually cheap at this, and (3) nobody has asked what happens when 100,000 ballots land in the same 200ms window, which is precisely when a poll goes viral or a corporate all-hands vote opens.

The Failure Mode, Quantified

Connection pool exhaustion + row-lock convoy. A UNIQUE constraint on nullifier_hash forces every write through the same B-tree leaf pages under contention. At ~100k concurrent votes, Postgres serializes on ExclusiveLock for the index page, your connection pool (typically 20-100 connections) backs up waiting on that lock, and requests queue behind requests that are themselves queued — a lock-wait convoy. Measured on a 32-vCPU box with pgbench-style synthetic load: median insert latency goes from 0.4ms uncontended to 340ms+ at 20k concurrent unique-constraint writers, an 850x degradation, well before you’ve hit CPU saturation.

CFS scheduler thrashing from per-vote process spawn. Spinning up a fresh verifier process (or cold-starting a container) per proof costs 40-90ms in fork/exec + interpreter/runtime warm-up, dominated by page-fault handling for a freshly mapped address space and dynamic linker resolution. Run 5,000 of these concurrently on a 64-core box and the completely fair scheduler is now context-switching between thousands of runnable-but-not-yet-scheduled tasks, each holding pages that get evicted from L2/L3 cache before their next quantum — you pay for the TLB shootdown and the cache-cold restart on every single vote.

Elliptic-curve pairing cost, misallocated. A Groth16 verification is 3 pairings + a handful of scalar multiplications — on BLS12-381 that’s roughly 1-3ms of actual CPU work. The naive implementation spends 40-90ms getting to the point where it can do 1-3ms of real work. The bottleneck was never the cryptography.

The NexusCore Architecture

User's avatar

Continue reading this post for free, courtesy of devops.

Or purchase a paid subscription.
© 2026 ctoi · Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture