---
title: "Credit Ledger Integrity"
description: "Learn how TurboPentest's credit ledger uses an append-only event log, with an independent SHA-256 hash computed over each event (and designed on-chain anchoring), to create a tamper-evident transaction history for every credit movement."
canonical: https://turbopentest.com/learn/reports-blockchain/credit-ledger-integrity
source: "TurboPentest Learn"
---

# Credit Ledger Integrity

## Credits as a Financial Record

TurboPentest operates on a credit-based model. Users purchase pentest credits, and each pentest consumes one credit of the selected tier (Recon, Audit-Ready, Threat-Hunt, or Adversarial-Depth, each with its own agent-hours allotment). These display names map to the canonical tier slugs the API and URLs use: Recon = `recon`, Audit-Ready = `standard`, Threat-Hunt = `deep`, Adversarial-Depth = `blitz`. This creates a financial record - a history of issuance, transfers, consumption, and expiry that must be accurate, complete, and tamper-evident.

Unlike traditional SaaS billing where a single monthly charge covers everything, a credit system has many individual lifecycle events. Each credit purchase, each pentest launch, each transfer, and each expiration is a separate event. The integrity of this history matters for billing disputes, financial audits, and user trust.

TurboPentest applies the same cryptographic infrastructure used for report attestation to the credit ledger: every event is recorded in an append-only log, and an independent SHA-256 hash is computed over each event's own fields. Those per-event hashes are designed to be batched and anchored on-chain. As with report attestation, on-chain publishing to Base is the roadmap and is not yet live - the tamper-evidence available today is the append-only log with an independent SHA-256 hash over each event. (Note: events are not linked into a hash chain - each event's hash covers only that event's own fields, with no previous-hash link between events - and per-event Merkle proofs are part of the not-yet-live roadmap.)

## Event-Based Ledger Architecture

The credit ledger is an append-only event log. Every action that affects a credit creates a new ledger event rather than modifying an existing record. Each credit itself is an individual record with a tier, agent-hours, and a status (available, scheduled, used, or expired); the ledger records the events that move credits through that lifecycle.

Each ledger event contains:

- **Event ID** - A unique identifier for this specific event
- **Credit ID** - The credit this event applies to
- **Event Type** - One of: issued, transferred, consumed, or expired
- **From/To User** - For transfers, the sending and receiving user IDs
- **Metadata** - What the event relates to (for example, the pentest ID, tier, and attestation hash for a consumed event)
- **Timestamp** - When the event occurred (server-side UTC)
- **Event Hash** - The SHA-256 hash of the event (see below)
- **Anchor reference** - Set once the event has been included in a Merkle anchor (populated when on-chain anchoring is live)

The ledger is treated as append-only: events are only ever inserted, each carries an independent SHA-256 hash over its own fields, and corrections are made by appending new events rather than editing history. The events are not chained together - one event's hash does not incorporate the previous event's hash - so altering one event does not by itself break a later event's hash. The only field written after creation is the anchor reference that links the event to its Merkle anchor (populated once on-chain anchoring is live).

## Event Hashing

When a ledger event is created, TurboPentest computes its hash over a canonical JSON serialization of the event's fields:

```
event_hash = SHA-256(canonical_json({
  creditId, eventType, fromUserId, toUserId, metadata, createdAt
}))
```

Because SHA-256 is deterministic and collision-resistant, the event hash is a fingerprint of exactly what happened: which credit, what kind of event, who was involved, what it referenced, and when. If any field of a recorded event were later altered - say, changing which pentest consumed a credit - recomputing the hash would produce a different value than the one stored and anchored.

When a pentest completes and its attestation is created, a consumed event is appended to the ledger with metadata linking the credit to the pentest and its attestation hash. This ties the billing record to the attested results: the credit's consumption and the pentest's attestation reference each other.

## On-Chain Anchoring (Designed)

A hash stored next to the data it protects is not enough on its own: an attacker with full database access could alter an event and recompute its hash. The strongest tamper evidence comes from anchoring the hashes somewhere the attacker cannot rewrite. This is the purpose of on-chain anchoring - which is TurboPentest's design and roadmap, not yet live (the anchoring contract is not yet deployed).

TurboPentest's anchoring job (the same one designed to anchor pentest attestations, covered in Module 4) is intended to run as a daily batch that:

1. Collects every ledger event hash and attestation hash that has not yet been anchored
2. Builds a Merkle tree from all collected hashes
3. Submits the Merkle root to Base L2 in a single transaction
4. Records the anchor (root hash, transaction hash, chain ID, block number, event count, and the batch's time period) and links every event in the batch to it

Once live, this creates an external, immutable reference point. If someone with database access altered an anchored ledger event - even recomputing its event hash to look internally consistent - the recomputed hashes could no longer produce the Merkle root recorded on Base. The intended anchoring frequency balances cost with security: a daily batch keeps the window of unanchored events small while keeping transaction costs negligible. Until anchoring is live, what protects the ledger is the append-only log with an independent SHA-256 hash over each event; because events are not chained and the on-chain anchor is not yet live, a database-level attacker who consistently recomputes an altered event's hash is exactly the case the roadmap anchoring is designed to close.

## Tamper Detection Scenarios

Once on-chain anchoring is live, the combination of event hashing and on-chain anchoring is designed to make several attack scenarios detectable. (Today, without the anchor and with no chaining between events, a database-level attacker who alters an event and recomputes its hash consistently is not caught by the per-event hash alone - closing this gap is exactly what the roadmap anchoring is for.)

### Modified Event

If someone changes a field of an anchored event (for example, redirecting a consumed event to a different pentest), the stored event hash no longer matches a recomputation from the event's fields. If they also recompute the stored hash, the Merkle root built from the batch's hashes no longer matches the root anchored on Base.

### Deleted Event

If someone removes an anchored event, the anchor's recorded event count and the set of leaf hashes no longer reproduce the anchored Merkle root.

### Inserted Event

If someone back-dates a fraudulent event into an already-anchored period, that event has no anchor reference, and it cannot be added to a historical batch - the on-chain root for that period is already fixed.

### Why the Anchor Matters

Without anchoring, a database-level attacker could rewrite events and hashes consistently. The on-chain Merkle root is the piece the attacker cannot touch: it is recorded on a public blockchain that TurboPentest itself cannot modify after the fact.

## Audit and Dispute Resolution

The hashed, anchored ledger provides powerful tools for auditing:

- **Billing disputes** - When a user disputes a charge, the event history shows every issuance, transfer, consumption, and expiry for their credits, each with an independent SHA-256 hash in the append-only log (and, once anchoring is live, committed to an on-chain anchor)
- **Attestation linkage** - Consumed events carry the pentest's attestation hash in their metadata, tying each spent credit to cryptographically attested results
- **Internal audits** - Administrators can recompute each event's SHA-256 hash from its fields and compare it against the stored hash; once on-chain anchoring is live, they can also rebuild the Merkle tree for each batch and compare its root against the anchor recorded on Base, providing external validation that history has not been rewritten
- **Financial record-keeping** - The append-only ledger, with an independent SHA-256 hash over each event (and designed on-chain anchoring), is built to meet audit trail expectations for financial record-keeping standards

## Implementation Considerations

Event hashing adds minimal overhead to ledger operations: SHA-256 computation takes microseconds, and hashing happens once at event creation. Anchoring is designed as a single daily batch job, so it adds no per-request cost.

Reading a user's credit balance does not require replaying the ledger: balances are computed from the credit records themselves (counts of available, scheduled, used, and expired credits by tier). The ledger exists as the audit trail layered on top - integrity verification is an on-demand operation, not a per-request cost.
