VDF Anti-Spam
The Spam Problem
Standard Messages have no bid and require a VDF proof for spam resistance. Without some mechanism, bots could flood the network with free messages.
What is a VDF?
A Verifiable Delay Function is a computation that:
Takes a minimum amount of sequential time to compute
Cannot be parallelized (no GPU speedup)
Can be verified quickly (much cheaper than computing)
This creates a natural rate limit: users must expend real-world time to submit messages, preventing spam floods without requiring monetary fees.
How Obsidian Uses VDF
Before submitting a free (SM) message, you must:
Get the challenge parameters from the network
Compute a sequential hash chain with checkpoints
Submit the proof with your message
1
eth_getMessageWork
Get iterations + checkpoint interval
2
Compute VDF
Sequential hash chain with checkpoints
3
eth_sendMessageBlob
Include checkpoints array
4
Verify
Node checks 3 random segments (Fiat-Shamir)
The Algorithm (Checkpointed Hash-Chain)
Obsidian's VDF is a checkpoint-based sequential hash chain (algorithm version VdfAlgHashChain = 1).
Step 1: Compute Challenge
The challenge binds the VDF proof to the specific message content.
Step 2: Compute Hash Chain
Each iteration depends on the previous one; you cannot skip ahead or parallelize.
Step 3: Store Checkpoints
Target checkpoint count: 10 (configurable via
checkpointCount)Checkpoint interval:
floor(iterations / checkpointCount)(minimum 1)Store intermediate values at each interval
Always include the final value
Example: With 11,000 iterations and 10 checkpoints:
Interval = 1,100
Checkpoints at iterations: 1100, 2200, 3300, ..., 10999
Step 4: Submit Proof
Include with your message:
vdfCheckpoints[]- Array of checkpoint hashesvdfCheckpointInterval- Spacing between checkpointsvdfIterations- Total iterations computedvdfAlgVersion- Algorithm version (currently1)
Iteration Scaling
Larger messages require more work:
Where payloadKB = floor(payloadBytes / 1024) (integer division).
0 KB
100,000
1 KB
110,000
4 KB
140,000
8 KB (max)
180,000
Default config: baseIterations = 100000, scalingIterationsPerKB = 10000
Performance estimates:
Browser JS: ~50,000–100,000 iterations/second
Native Go: ~500,000 iterations/second
Verification (Fiat-Shamir Selection)
Nodes don't recompute the entire hash chain. Instead:
Build Fiat-Shamir seed:
Select 3 checkpoints deterministically:
Verify each selected segment by recomputing from the previous checkpoint
This is a spot check: verifying 3 random segments from ~10 checkpoints gives cheat probability of (1/10)³ = 0.1% per attempt.
Security constant: NumCheckpointsToVerify = 3 is hardcoded and not configurable for security reasons.
Code Example
JavaScript (Browser/Node)
Why It Stops Spam
Normal user
1 device
~1 msg/sec - totally fine
Bot with 1 CPU
Sequential only
~1 msg/sec - same as user
Bot with 1000 CPUs
Still sequential
~1 msg/sec per CPU - expensive
Bot with GPUs
Can't parallelize
No advantage
The key insight: time cannot be bought. Even with unlimited hardware, each message takes minimum ~1 second.
Priority Messages Skip VDF
PM messages (with bids >= network MinPMBid) don't require VDF:
They pay real money, which is its own spam deterrent
Time-sensitive messages shouldn't wait for VDF computation
Economic cost replaces computational cost
Configuration
Networks configure VDF via genesis messageConfig.vdfConfig:
Example genesis config:
Verification Errors
ErrVdfDisabled
VDF disabled but proof submitted
ErrVdfVersionMismatch
Algorithm version doesn't match network config
ErrVdfInsufficientWork
Submitted iterations < required for payload
ErrVdfNoCheckpoints
Empty checkpoints array
ErrVdfInvalidInterval
Checkpoint interval is 0 or doesn't match expected
ErrVdfCheckpointMismatch
Fiat-Shamir verification of segments failed
Source Files
messaging/vdf.go
VDF computation and verification
params/config.go
MessageVdfConfig struct
internal/ethapi/api_message.go
eth_getMessageWork RPC
Next: Permanent On-Chain Data - Why Obsidian data lasts forever
Last updated