State-Based CRDT
GUN’s conflict resolution is built on the concept of state timestamps - each property update includes a monotonically increasing timestamp that determines which value wins.How It Works
Every update in GUN includes metadata:~/workspace/source/src/state.js:18-27
State Vector Clocks
State Generation
GUN generates unique, monotonically increasing timestamps:~/workspace/source/src/state.js:4-10
Components
- Base timestamp: Milliseconds since epoch
- Sub-millisecond counter: Allows multiple updates within the same millisecond
- Drift compensation: Accounts for clock skew across machines
~/workspace/source/src/state.js:12
Getting State Values
~/workspace/source/src/state.js:13-17
Setting State Values
~/workspace/source/src/state.js:18-27
Last-Write-Wins (LWW)
GUN uses a Last-Write-Wins strategy at the property level, not the document level.Property-Level Resolution
Why Property-Level?
This approach provides better merge semantics:Handling Conflicts
Automatic Merging
GUN automatically merges concurrent updates:Conflict Detection
You can detect conflicts by tracking state changes:Dealing with Clock Skew
Drift Compensation
GUN includes a drift parameter to handle clock differences:~/workspace/source/src/state.js:11
Best Practices
- Use NTP: Keep system clocks synchronized
- Trust timestamps: Don’t try to “fix” timestamps
- Monotonic clocks: GUN ensures timestamps always increase locally
Advanced Conflict Strategies
Counter CRDTs
For counters, use increment operations:Set CRDTs
GUN’s.set() implements a grow-only set:
Custom Resolution
Implement custom conflict resolution by tracking versions:Vector Clocks vs State Timestamps
GUN uses state timestamps rather than traditional vector clocks:Vector Clocks
State Timestamps (GUN)
- Simpler to implement and reason about
- Constant space per property (not per peer)
- Works well for eventually consistent systems
- Natural ordering with timestamps
- Requires reasonably synchronized clocks
- Cannot detect all concurrent updates (some are arbitrarily resolved)
- May lose updates if clocks are severely misaligned
Data Integrity
Hash-Based Deduplication
GUN uses content hashing to detect duplicate messages:~/workspace/source/src/mesh.js:73
Preventing Loops
The mesh layer prevents infinite message loops:~/workspace/source/src/mesh.js:76
Convergence Guarantees
Eventual Consistency
GUN guarantees that all peers will eventually converge to the same state:- All updates are commutative: Order doesn’t matter
- All updates are idempotent: Applying twice has same effect
- All peers use the same merge rules: Deterministic conflict resolution
Convergence Time
The time to convergence depends on:- Network latency between peers
- Number of hops in the mesh network
- Message batching intervals
- Peer availability
Testing Conflicts
Simulating Offline Scenarios
Concurrent Writes
Best Practices
- Embrace eventual consistency: Don’t rely on immediate consensus
- Use property-level updates: More granular merging
- Avoid read-modify-write: Use semantic operations instead
- Implement tombstones: Mark deletions rather than removing data
- Monitor state timestamps: Debug sync issues
- Trust the CRDT: Don’t try to “fix” conflicts manually
- Design for commutativity: Order-independent operations
- Test offline scenarios: Ensure your app handles partitions gracefully
Common Patterns
Optimistic UI Updates
Collaborative Editing
Debugging
Inspecting State Metadata
Monitoring Conflicts
Next Steps
- Optimize Performance for high-throughput scenarios
- Understand CAP Theorem tradeoffs in GUN
- Learn about Networking protocols
- Deploy to Production with confidence