Hero Sample — TamperProof
Concept: Hash-chained event streams catch direct-DB tampering at the next verification pass. The full why lives in the Tamper-Evident Streams concept page; this is the runnable proof.
- Code:
samples/Stratara.Sample.TamperProof - Lines: ~100
- Read time: 5–10 min
- Dependencies: none — pure in-memory, no database, no DI container.
What you'll see
HashChainedEventStore— everyAppendcomputesSHA-256(previousHash || canonical-json(payload))and stores both the entry's own hash and a pointer to the previous entry's hash.- Three events appended —
AccountOpened,AmountDeposited,AmountWithdrawn. The console prints each entry with a six-byte hash preview so the chain is visually inspectable. ChainVerifier.Verify— the clean run passes. Every stored hash matches a fresh re-hash; every previous-hash pointer matches the prior entry's hash.TamperWithPayloadForDemo— simulates an attacker editing entry #2 directly in the database, rewriting$50to$5000. The stored hash is untouched.ChainVerifier.Verifyagain — raisesEventStreamCorruptedExceptionat sequence #2 with a precise reason: "stored hash does not match a fresh re-hash of the payload (payload was modified after commit)".
Running
dotnet run --project samples/Stratara.Sample.TamperProof
Expected output (abridged):
=== Stratara TamperProof ===
--- Append three events ---
#1 AccountOpened hash=70be4f…
#2 AmountDeposited hash=796018…
#3 AmountWithdrawn hash=6a0260…
--- Verify the chain (clean) ---
OK — every entry's stored hash matches a fresh re-hash of its payload.
OK — every entry's previous-hash pointer matches the prior entry's hash.
--- Tamper: rewrite entry #2's deposit from $50 to $5000 ---
--- Verify the chain (tampered) ---
CAUGHT: Event stream tampering detected at sequence #2: stored hash does not match a fresh re-hash of the payload (payload was modified after commit)
How this maps to the real Stratara
| Sample | Real Stratara |
|---|---|
HashChainedEventStore (in-memory list) |
Hash columns on event_stream_entry populated by EF Core |
ChainVerifier.Verify (on-demand) |
EventStreamHashingWorker from the Stratara.EventSourcing.WorkerDefaults composite — runs as a background service, processes batches, surfaces breaks via OpenTelemetry counters + structured logs |
TamperWithPayloadForDemo |
No equivalent — production code has no public mutation path on persisted entries |
Sister hero sample
- Hero Sample — Encryption — the confidentiality counterpart. Same goal of integrity-by-construction, applied at the field level instead of the stream level.