# The fuzz engine

The fuzz engine drives instruction handlers with randomised inputs and reports invariant breaches. This chapter describes what is generated, how the runtime executes a generated input, and which categories of bug the engine does and does not catch.

## Input generation

For each instruction in the IDL, the engine enumerates the instruction's argument list and account list and produces a sequence of input vectors. Each vector is a complete set of arguments and a complete set of account references.

Arguments are generated by type:

| IDL type                  | strategy                                                                                    |
| ------------------------- | ------------------------------------------------------------------------------------------- |
| `u8`, `u16`, `u32`, `u64` | uniform across the type's full range, with a 5% bias toward zero, `MAX`, and `MAX-1`        |
| `i8`–`i64`                | uniform across the signed range, with the same bias plus `MIN` and `MIN+1`                  |
| `bool`                    | uniform                                                                                     |
| `string`                  | random UTF-8 strings of random length up to 4 KiB; 1% of strings are deliberately malformed |
| `pubkey`                  | drawn from the snapshot's account set                                                       |
| arrays, vecs              | length drawn from a long-tail distribution biased toward 0 and 1                            |
| structs                   | recursive                                                                                   |

Accounts are drawn from the snapshot. An account constraint that requires a specific PDA seed is honoured: the engine derives the PDA from the seed and uses the result. An account constraint that requires a `Signer` is honoured by minting a fresh keypair and including its signature in the transaction wrapper.

## Runtime

Each vector is executed against a TypeScript reimplementation of the relevant Anchor and SPL primitives. The runtime is intentionally not the BPF interpreter: a faithful BPF interpreter would cost the developer most of the speed budget that makes fuzzing useful in the first place. The trade-off is documented at the foot of this chapter.

The runtime maintains a working copy of the snapshot. After each instruction, it diffs the working copy against the original and emits a structured event for each changed account. Invariants are evaluated against this diff.

## Invariants

The engine evaluates two classes of invariant. *Local* invariants are predicates over a single instruction's diff; for example, "no account loses more lamports than it had". *Global* invariants are predicates over the cumulative diff across the entire fuzz run; for example, "the sum of all token balances is conserved across fuzz iterations".

When an invariant breaches, the engine records the input vector that caused the breach, the current PRNG seed, and a minimal reproducer. The reproducer is a single-instruction transaction that replays the breach against the snapshot, suitable for committing into a regression test.

## What the engine catches

The engine reliably catches:

* account-validation bugs, where an instruction accepts an account it should reject;
* arithmetic bugs, where unchecked arithmetic over- or underflows;
* ordering bugs, where a CPI is issued before a state mutation that the CPI should have observed;
* balance-conservation bugs, where the sum of relevant lamports or token amounts changes unexpectedly.

## What the engine does not catch

The engine is blind to:

* BPF-specific bugs, such as stack-overflow miscalculations or compute-unit exhaustion;
* bugs whose root cause is a deviation between the validator's runtime and the engine's runtime;
* bugs whose trigger requires more than one transaction, unless the user has configured a multi-tx scenario;
* bugs in programs the engine does not have the IDL for.

These limits are not bugs in the engine; they are an honest statement of the design space. For BPF-specific behaviour, the recipe [Reproducing mainnet bugs locally](/solanatestforge-docs/part-iii-recipes/reproducing-mainnet-bugs.md) recommends pairing the fuzz output with `solana-test-validator` for a final confirmation pass.

## Determinism

A fuzz run is deterministic if and only if the PRNG seed is fixed. The seed can be set in `.solforge.toml` under `[fuzz].seed`, or on the command line via `--seed <int>`. When neither is supplied, the engine draws a seed from the operating system and prints it on the first line of output, so that an interesting run can be re-run with the same seed.

In practice, the most useful seeds are the ones that surprised the developer. Pinning a seed is appropriate for regression tests; for ongoing development, the default non-determinism is the recommendation.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://solanatestforge.gitbook.io/solanatestforge-docs/part-ii-reference/fuzz-engine.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
