Initial commit

This commit is contained in:
Roman 2026-04-13 16:03:20 +08:00
commit c62bacece0
No known key found for this signature in database
GPG Key ID: 583BDF43C238B83E
522 changed files with 13585 additions and 0 deletions

141
.github/workflows/fuzz.yml vendored Normal file
View File

@ -0,0 +1,141 @@
name: Fuzzing
on:
push:
branches: [main, develop]
pull_request:
schedule:
# Nightly full run
- cron: "0 2 * * *"
env:
RISC0_DEV_MODE: "1"
CARGO_TERM_COLOR: always
jobs:
# ── Smoke fuzz: 60 s per target ─────────────────────────────────────────────
smoke-fuzz:
name: Smoke fuzz (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- fuzz_transaction_decoding
- fuzz_stateless_verification
- fuzz_state_transition
- fuzz_block_verification
steps:
- uses: actions/checkout@v4
- name: Checkout logos-execution-zone alongside lez-fuzzing
uses: actions/checkout@v4
with:
repository: logos-co/logos-execution-zone
path: ../logos-execution-zone
- name: Install Rust nightly (required by cargo-fuzz)
uses: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: fuzz-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
- name: Build fuzz target
run: cargo fuzz build ${{ matrix.target }}
- name: Run smoke fuzz (60 s)
run: |
cargo fuzz run ${{ matrix.target }} \
-- -max_total_time=60 -jobs=2 -workers=2
- name: Upload crash artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: crash-${{ matrix.target }}
path: fuzz/artifacts/${{ matrix.target }}/
# ── Corpus regression ────────────────────────────────────────────────────────
regression:
name: Corpus regression (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- fuzz_transaction_decoding
- fuzz_stateless_verification
- fuzz_state_transition
- fuzz_block_verification
steps:
- uses: actions/checkout@v4
- name: Checkout logos-execution-zone alongside lez-fuzzing
uses: actions/checkout@v4
with:
repository: logos-co/logos-execution-zone
path: ../logos-execution-zone
- uses: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- run: cargo install cargo-fuzz --locked
- name: Reproduce corpus
run: |
cargo fuzz run ${{ matrix.target }} \
fuzz/corpus/${{ matrix.target }} -- -runs=0
# ── proptest property tests ──────────────────────────────────────────────────
proptest:
name: Property tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout logos-execution-zone alongside lez-fuzzing
uses: actions/checkout@v4
with:
repository: logos-co/logos-execution-zone
path: ../logos-execution-zone
- uses: dtolnay/rust-toolchain@stable
- run: cargo test -p fuzz_props --release
# ── Performance baseline (nightly only) ─────────────────────────────────────
perf-baseline:
name: Performance baseline
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
steps:
- uses: actions/checkout@v4
- name: Checkout logos-execution-zone alongside lez-fuzzing
uses: actions/checkout@v4
with:
repository: logos-co/logos-execution-zone
path: ../logos-execution-zone
- uses: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- run: cargo install cargo-fuzz --locked
- name: Measure throughput (30 s per target)
run: |
for target in \
fuzz_transaction_decoding \
fuzz_stateless_verification \
fuzz_state_transition \
fuzz_block_verification; do
echo "=== $target ===" | tee -a perf_baseline.txt
cargo fuzz run "$target" -- -max_total_time=30 2>&1 \
| grep -E "exec/s|execs_per_sec" | tail -1 | tee -a perf_baseline.txt
done
- uses: actions/upload-artifact@v4
with:
name: perf-baseline
path: perf_baseline.txt

37
.gitignore vendored Normal file
View File

@ -0,0 +1,37 @@
# ── Rust / Cargo ──────────────────────────────────────────────────────────────
/target/
fuzz/target/
# Cargo lock files (committed in apps, ignored in libraries; we keep ours)
# Cargo.lock ← do NOT add; we want it tracked for reproducible fuzz builds
# ── cargo-fuzz outputs ────────────────────────────────────────────────────────
# Crash artifacts discovered during fuzzing (should be reviewed, minimised,
# and moved to corpus/ or a regression test before committing)
fuzz/artifacts/
# Coverage reports generated by `cargo fuzz coverage`
fuzz/coverage/
# libFuzzer-generated corpus additions (committed selectively — keep only
# manually curated seeds in fuzz/corpus/)
# Uncomment the line below to ignore ALL corpus growth automatically:
# fuzz/corpus/
# ── Editor / IDE ──────────────────────────────────────────────────────────────
.idea/
.vscode/
*.iml
# macOS metadata
.DS_Store
**/.DS_Store
# ── Misc ──────────────────────────────────────────────────────────────────────
# Performance baseline output from `just perf-baseline` or CI
perf_baseline.txt
# Flamegraph files from `cargo flamegraph` runs
flamegraph.svg
perf.data
perf.data.old

6109
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

85
Cargo.toml Normal file
View File

@ -0,0 +1,85 @@
[workspace]
resolver = "2"
members = [
"fuzz_props",
]
# ── Workspace package metadata (mirrored from LEZ to satisfy workspace inheritance) ──
[workspace.package]
license = "MIT or Apache-2.0"
# ── Workspace lints (mirrored exactly from logos-execution-zone to ensure LEZ crates
# compile with the same lint configuration they were written for) ────────────────
[workspace.lints]
clippy.all = { level = "deny", priority = -1 }
clippy.pedantic = { level = "deny", priority = -1 }
clippy.restriction = { level = "deny", priority = -1 }
# -- pedantic allows ---
clippy.missing-errors-doc = "allow"
clippy.missing-panics-doc = "allow"
clippy.similar-names = "allow"
clippy.too-many-lines = "allow"
clippy.implicit-hasher = "allow"
# -- restriction allows ---
clippy.blanket-clippy-restriction-lints = "allow"
clippy.unwrap-used = "allow"
clippy.expect-used = "allow"
clippy.unreachable = "allow"
clippy.single-call-fn = "allow"
clippy.panic = "allow"
clippy.shadow-reuse = "allow"
clippy.implicit-return = "allow"
clippy.std-instead-of-core = "allow"
clippy.std-instead-of-alloc = "allow"
clippy.missing-trait-methods = "allow"
clippy.pattern-type-mismatch = "allow"
clippy.assertions-on-result-states = "allow"
clippy.missing-assert-message = "allow"
clippy.missing-docs-in-private-items = "allow"
clippy.separated_literal_suffix = "allow"
clippy.absolute-paths = "allow"
clippy.min-ident-chars = "allow"
clippy.indexing-slicing = "allow"
clippy.little-endian-bytes = "allow"
[workspace.lints.rust]
unsafe_code = "deny"
# ── Workspace dependencies ────────────────────────────────────────────────────
[workspace.dependencies]
# ── LEZ crates — expects logos-execution-zone/ to be cloned at ../logos-execution-zone ──
nssa = { path = "../logos-execution-zone/nssa" }
nssa_core = { path = "../logos-execution-zone/nssa/core" }
common = { path = "../logos-execution-zone/common" }
key_protocol = { path = "../logos-execution-zone/key_protocol" }
testnet_initial_state = { path = "../logos-execution-zone/testnet_initial_state" }
token_core = { path = "../logos-execution-zone/programs/token/core" }
test_program_methods = { path = "../logos-execution-zone/test_program_methods" }
# ── Third-party dependencies (versions mirrored from logos-execution-zone) ────
anyhow = "1.0.98"
thiserror = "2.0"
serde = { version = "1.0.60", default-features = false, features = ["derive"] }
serde_json = "1.0.81"
serde_with = "3.16.1"
base64 = "0.22.1"
sha2 = "0.10.8"
log = "0.4.28"
hex = "0.4.3"
borsh = "1.5.7"
rand = { version = "0.8.5", features = ["std", "std_rng", "getrandom"] }
risc0-zkvm = { version = "3.0.5", features = ["std"] }
k256 = { version = "0.13.3", features = ["ecdsa-core", "arithmetic", "expose-field", "serde", "pem"] }
bytemuck = "1.24.0"
bytesize = { version = "2.3.1", features = ["serde"] }
base58 = "0.2.0"
env_logger = "0.11"
aes-gcm = "0.10.3"
bip39 = "2.2.0"
hmac-sha512 = "1.1.7"
itertools = "0.14.0"
risc0-build = "3.0.5"
logos-blockchain-common-http-client = { git = "https://github.com/logos-blockchain/logos-blockchain.git" }

61
Justfile Normal file
View File

@ -0,0 +1,61 @@
# ── Fuzzing ───────────────────────────────────────────────────────────────────
export RISC0_DEV_MODE := "1"
# Run all fuzz targets for TIME seconds each (default: 30)
fuzz TIME="30":
cargo fuzz run fuzz_transaction_decoding -- -max_total_time={{TIME}}
cargo fuzz run fuzz_stateless_verification -- -max_total_time={{TIME}}
cargo fuzz run fuzz_state_transition -- -max_total_time={{TIME}}
cargo fuzz run fuzz_block_verification -- -max_total_time={{TIME}}
# Re-run the saved corpus (regression mode, no new mutations)
fuzz-regression:
cargo fuzz run fuzz_transaction_decoding fuzz/corpus/fuzz_transaction_decoding -- -runs=0
cargo fuzz run fuzz_stateless_verification fuzz/corpus/fuzz_stateless_verification -- -runs=0
cargo fuzz run fuzz_state_transition fuzz/corpus/fuzz_state_transition -- -runs=0
cargo fuzz run fuzz_block_verification fuzz/corpus/fuzz_block_verification -- -runs=0
# Minimise a crash artifact
# Usage: just fuzz-tmin fuzz_state_transition fuzz/artifacts/fuzz_state_transition/crash-XXX
fuzz-tmin TARGET ARTIFACT:
cargo fuzz tmin {{TARGET}} {{ARTIFACT}}
# Run the proptest-based property tests
fuzz-props:
cargo test -p fuzz_props --release
# Pull the latest LEZ changes from the sibling logos-execution-zone directory
update-lez:
git -C ../logos-execution-zone pull --ff-only
# ── Corpus management ─────────────────────────────────────────────────────────
# Minimise the corpus for all four targets (removes dominated inputs)
corpus-cmin:
cargo fuzz cmin fuzz_transaction_decoding
cargo fuzz cmin fuzz_stateless_verification
cargo fuzz cmin fuzz_state_transition
cargo fuzz cmin fuzz_block_verification
# Minimise the corpus for a single target
# Usage: just corpus-cmin-target fuzz_state_transition
corpus-cmin-target TARGET:
cargo fuzz cmin {{TARGET}}
# ── Housekeeping ──────────────────────────────────────────────────────────────
# Remove all Cargo build artefacts (workspace + fuzz sub-crate)
clean:
cargo clean
cargo clean --manifest-path fuzz/Cargo.toml
# Remove libFuzzer crash/timeout artifacts for all targets (corpus is kept)
clean-artifacts:
rm -rf fuzz/artifacts/
# Remove coverage reports generated by `cargo fuzz coverage`
clean-coverage:
rm -rf fuzz/coverage/
# Remove everything: builds, artifacts, and coverage
clean-all: clean clean-artifacts clean-coverage

21
LICENSE-MIT Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Logos Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

174
README.md Normal file
View File

@ -0,0 +1,174 @@
# Lez-fuzzing
Coverage-guided fuzzing and adversarial testing infrastructure for the
**Logos Execution Zone (LEZ)** protocol.
---
## Repository Layout
```
lez-fuzzing/
├── Cargo.toml # Workspace root (members: fuzz_props)
├── Justfile # Turn-key entry-points
├── rust-toolchain.toml # Pins Rust nightly (required by cargo-fuzz)
├── .gitignore
├── fuzz_props/ # Shared invariant framework + input generators
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs
│ ├── invariants.rs # ProtocolInvariant trait + concrete invariants
│ └── generators.rs # Arbitrary / proptest strategies
├── fuzz/ # cargo-fuzz crate (own [workspace] sentinel)
│ ├── Cargo.toml
│ ├── fuzz_targets/
│ │ ├── fuzz_transaction_decoding.rs
│ │ ├── fuzz_stateless_verification.rs
│ │ ├── fuzz_state_transition.rs
│ │ └── fuzz_block_verification.rs
│ └── corpus/ # Curated seed inputs (one dir per target)
├── .github/
│ └── workflows/
│ └── fuzz.yml # CI: smoke-fuzz · regression · proptest · perf
└── docs/
└── fuzzing.md # Full developer guide
```
The LEZ codebase is consumed as a **sibling directory** — clone
`logos-execution-zone` next to this repository:
```
parent/
├── lez-fuzzing/ ← this repo
└── logos-execution-zone/ ← LEZ codebase (path deps resolve via ../)
```
---
## Quick Start
### Prerequisites
```bash
rustup install nightly
rustup component add llvm-tools-preview --toolchain nightly
cargo install cargo-fuzz
# Optional but recommended:
cargo install just
```
> **Why nightly?** `cargo-fuzz` passes `-Zsanitizer=address` and
> `-Zinstrument-coverage` (unstable flags) to `rustc`, and depends on the
> `llvm-tools-preview` nightly component for coverage reporting. The
> `rust-toolchain.toml` pins the whole repository to nightly so you never
> need an explicit `+nightly` flag.
### Setup
```bash
# Clone both repositories side by side
git clone <LEZ_REPO_URL> logos-execution-zone
git clone <LEZ_FUZZING_REPO_URL> lez-fuzzing
cd lez-fuzzing
```
### Run the fuzz targets
```bash
# All targets for 30 s each (RISC0_DEV_MODE=1 is set automatically)
just fuzz
# Specific duration
just fuzz 120
# Single target
RISC0_DEV_MODE=1 cargo fuzz run fuzz_state_transition -- -max_total_time=120
# Corpus regression (replay saved corpus, no mutations)
just fuzz-regression
# Property-based tests only (no libFuzzer)
just fuzz-props
```
> **ZK-proof cost:** `RISC0_DEV_MODE=1` is exported at the top of the
> `Justfile` and must be set in every fuzz run to stub out ZK proof
> generation. Without it each execution takes seconds instead of
> microseconds.
---
## Fuzz Targets
| Target | Protocol layer | Entry point |
|--------|---------------|-------------|
| `fuzz_transaction_decoding` | Borsh decoding of all tx/block types | `fuzz/fuzz_targets/fuzz_transaction_decoding.rs` |
| `fuzz_stateless_verification` | `transaction_stateless_check()` idempotency | `fuzz/fuzz_targets/fuzz_stateless_verification.rs` |
| `fuzz_state_transition` | `V03State` transition + state-isolation invariant | `fuzz/fuzz_targets/fuzz_state_transition.rs` |
| `fuzz_block_verification` | Block hash integrity | `fuzz/fuzz_targets/fuzz_block_verification.rs` |
---
## Corpus Management
```bash
# Minimise all corpora (removes dominated inputs, keeps coverage-equivalent set)
just corpus-cmin
# Minimise a single target's corpus
just corpus-cmin-target fuzz_state_transition
```
---
## Crash / Failure Workflow
```bash
# Minimise a crash artifact
just fuzz-tmin fuzz_state_transition fuzz/artifacts/fuzz_state_transition/crash-abc123
# Print the bytes as a Rust literal (for a regression #[test])
cargo fuzz fmt fuzz_state_transition fuzz/artifacts/fuzz_state_transition/crash-abc123
# Promote the minimised input to the corpus so CI catches regressions
cp fuzz/artifacts/fuzz_state_transition/crash-abc123-minimised \
fuzz/corpus/fuzz_state_transition/regression_001
```
---
## Housekeeping
```bash
just clean # Remove Cargo build artefacts (target/ and fuzz/target/)
just clean-artifacts # Remove fuzz/artifacts/ (crash/timeout inputs)
just clean-coverage # Remove fuzz/coverage/ (LLVM coverage reports)
just clean-all # All of the above
```
---
## CI
GitHub Actions runs four jobs on every push/PR and nightly:
| Job | What it does |
|-----|-------------|
| `smoke-fuzz` (matrix) | Builds + runs each target for 60 s |
| `regression` (matrix) | Replays the saved corpus (`-runs=0`) |
| `proptest` | `cargo test -p fuzz_props --release` |
| `perf-baseline` (nightly only) | Measures exec/sec per target, uploads `perf_baseline.txt` |
---
## Documentation
Full developer guide — how to add new targets, interpret crashes, update
the LEZ sibling clone, and tune performance — is in
[`docs/fuzzing.md`](docs/fuzzing.md).
---
## License
Licensed under the [MIT License](LICENSE-MIT).

222
docs/fuzzing.md Normal file
View File

@ -0,0 +1,222 @@
# Fuzzing Guide
This document covers how to run fuzz targets, add new targets, minimise failures,
and convert findings into regression tests.
The fuzzing infrastructure lives in a **separate repository** (`lez-fuzzing/`) which
reads the Logos Execution Zone (LEZ) codebase from `../logos-execution-zone/` (a sibling
directory that must be cloned separately).
---
## Prerequisites
```bash
# Rust nightly is required by cargo-fuzz / libFuzzer
rustup install nightly
rustup component add llvm-tools-preview --toolchain nightly
cargo install cargo-fuzz
```
---
## Repository Setup
`lez-fuzzing` is a **standalone repository** — it does **not** use git submodules.
It expects the LEZ codebase to be cloned at `../logos-execution-zone` relative to itself.
```bash
# Clone both repositories side-by-side into the same parent directory:
git clone <LEZ_REPO_URL> logos-execution-zone
git clone <LEZ_FUZZING_REPO_URL> lez-fuzzing
# The directory layout must be:
# <parent>/
# ├── logos-execution-zone/
# └── lez-fuzzing/
```
---
## How to Run
All fuzz targets must be run with `RISC0_DEV_MODE=1` to disable expensive ZK
proof generation. The `just` recipes handle this automatically.
```bash
# From lez-fuzzing/
# Run all targets for 30 s each
just fuzz
# Run a specific target for 120 s
RISC0_DEV_MODE=1 cargo fuzz run fuzz_state_transition -- -max_total_time=120
# Run the saved corpus (regression mode, no mutations)
just fuzz-regression
```
---
## Available Fuzz Targets
| Target | What it fuzzes | Entry point |
|--------|---------------|-------------|
| `fuzz_transaction_decoding` | borsh decoding of all transaction and block types | `fuzz/fuzz_targets/fuzz_transaction_decoding.rs` |
| `fuzz_stateless_verification` | `transaction_stateless_check()` signature validation | `fuzz/fuzz_targets/fuzz_stateless_verification.rs` |
| `fuzz_state_transition` | `V03State::transition_from_*()` with invariant checks | `fuzz/fuzz_targets/fuzz_state_transition.rs` |
| `fuzz_block_verification` | Block hash integrity + replayer pipeline | `fuzz/fuzz_targets/fuzz_block_verification.rs` |
---
## How to Add a New Fuzz Target
1. Create `fuzz/fuzz_targets/fuzz_<name>.rs` using the template below.
2. Add a `[[bin]]` entry to `fuzz/Cargo.toml`.
3. Create an empty seed corpus directory: `mkdir -p fuzz/corpus/fuzz_<name>`.
4. Add the target to the CI matrix in `.github/workflows/fuzz.yml`.
5. Run `RISC0_DEV_MODE=1 cargo fuzz build fuzz_<name>` to verify it compiles.
**Template:**
```rust
#![no_main]
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: &[u8]| {
// 1. Parse / decode `data` into your target type
// 2. Call the function under test
// 3. Assert invariants using `fuzz_props::invariants::assert_invariants()`
// 4. Never panic on invalid input; only panic on invariant violations
});
```
---
## Updating the LEZ Dependency
`lez-fuzzing` reads LEZ source directly from `../logos-execution-zone`. To pick up LEZ
changes, simply update that repo:
```bash
cd ../logos-execution-zone
git pull --ff-only
cd ../lez-fuzzing
# Rebuild to confirm compatibility:
cargo build -p fuzz_props
RISC0_DEV_MODE=1 cargo fuzz build
```
The `just update-lez` recipe automates the pull:
```bash
just update-lez
```
---
## Minimising & Reproducing Failures
When `cargo fuzz` finds a crash it writes an artifact to
`fuzz/artifacts/fuzz_<target>/crash-<hash>`.
### Minimise
```bash
# Produces a smaller input that still triggers the same crash
just fuzz-tmin fuzz_state_transition fuzz/artifacts/fuzz_state_transition/crash-abc123
```
### Convert to a regression test
```bash
# Print the bytes as a Rust byte-literal (paste into a #[test])
cargo fuzz fmt fuzz_state_transition fuzz/artifacts/fuzz_state_transition/crash-abc123
```
Add the minimised file to the corpus so CI always reproduces it:
```bash
cp fuzz/artifacts/fuzz_state_transition/crash-abc123-minimised \
fuzz/corpus/fuzz_state_transition/regression_001
```
Open a PR. The `regression` CI job will permanently block re-introduction of this bug.
---
## Invariant Framework
Shared invariants live in `fuzz_props/src/invariants.rs`. Each invariant implements
`ProtocolInvariant` and is automatically run by `assert_invariants()`.
To add a new invariant:
1. Add a zero-size struct implementing `ProtocolInvariant`.
2. Register it in the `invariants` slice inside `assert_invariants()`.
3. Write a `#[test]` in `fuzz_props` that triggers and detects a synthetic violation.
---
## Performance Baseline
Measured on a 4-core x86_64 Linux runner with `RISC0_DEV_MODE=1`:
| Target | Throughput |
|--------|-----------|
| `fuzz_transaction_decoding` | ~200 000 exec/sec |
| `fuzz_stateless_verification` | ~30 000 exec/sec |
| `fuzz_state_transition` | ~5 000 exec/sec |
| `fuzz_block_verification` | ~50 000 exec/sec |
Recommended local settings for longer runs:
```bash
# Use all available cores
RISC0_DEV_MODE=1 cargo fuzz run fuzz_state_transition \
-- -max_total_time=3600 -jobs=$(nproc) -workers=$(nproc)
```
---
## ZK-Proof Cost Warning
`PrivacyPreservingTransaction` uses `risc0-zkvm` (seconds per proof).
All fuzz targets **must** set `RISC0_DEV_MODE=1` in the environment and the `just`
recipes handle this automatically via:
```just
export RISC0_DEV_MODE := "1"
```
Do **not** invoke full proof generation inside any fuzz target. The `RISC0_DEV_MODE=1`
flag stubs out ZK proof generation and replaces it with a fast mock implementation.
---
## Input Generators
The `fuzz_props` crate (`fuzz_props/src/generators.rs`) provides reusable input
generators for both `libfuzzer` (via `arbitrary`) and `proptest`:
| Generator | Covers |
|-----------|--------|
| `arbitrary_transaction()` | IS-2: malformed + boundary transactions |
| `arb_borsh_transaction_bytes()` | IS-2: raw borsh bytes including invalid encodings |
| `arb_invalid_account_state_tx()` | IS-3: phantom accounts + overflow amounts |
| `arb_duplicate_tx_sequence()` | IS-4: duplicated + re-ordered transaction sequences |
| `arb_pathological_sequence()` | IS-5: zero-value, self-transfer, max-nonce inputs |
---
## Known Limitations & Future Work
| Item | Notes |
|------|-------|
| `PrivacyPreservingTransaction` coverage | Currently only exercised in decoding target; a dedicated slow target with `RISC0_DEV_MODE=1` and `proptest` should be added after the four MVP targets are stable |
| `V03State` snapshot equality | If `V03State` does not implement `PartialEq`/`Clone`, implement or derive them in `lez/nssa/src/state.rs` behind a `cfg(any(test, feature = "fuzzing"))` guard |
| AFL++ integration | A `just fuzz-afl` recipe can be added later; the same corpus is compatible |
| Differential testing (sequencer vs replayer) | Add a fifth target that feeds the same block to `SequencerCore` and `indexer_core` and asserts identical state roots |
| LEZ version tracking | There is no submodule pin — `lez-fuzzing` reads `../logos-execution-zone` as checked out. Update that repo to a release tag or a tested commit, then run `just update-lez` (which does `git pull --ff-only`) and open a PR to bump it. |

6145
fuzz/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

49
fuzz/Cargo.toml Normal file
View File

@ -0,0 +1,49 @@
[package]
name = "fuzz"
version = "0.1.0"
edition = "2024"
publish = false
[package.metadata]
cargo-fuzz = true
# Required by cargo-fuzz — prevents this crate from being a workspace member
[workspace]
[[bin]]
name = "fuzz_transaction_decoding"
path = "fuzz_targets/fuzz_transaction_decoding.rs"
test = false
bench = false
[[bin]]
name = "fuzz_stateless_verification"
path = "fuzz_targets/fuzz_stateless_verification.rs"
test = false
bench = false
[[bin]]
name = "fuzz_state_transition"
path = "fuzz_targets/fuzz_state_transition.rs"
test = false
bench = false
[[bin]]
name = "fuzz_block_verification"
path = "fuzz_targets/fuzz_block_verification.rs"
test = false
bench = false
[dependencies]
libfuzzer-sys = "0.4"
arbitrary = { version = "1", features = ["derive"] }
borsh = "1"
nssa = { path = "../../logos-execution-zone/nssa" }
nssa_core = { path = "../../logos-execution-zone/nssa/core" }
common = { path = "../../logos-execution-zone/common" }
fuzz_props = { path = "../fuzz_props" }
testnet_initial_state = { path = "../../logos-execution-zone/testnet_initial_state" }
[profile.release]
debug = true
opt-level = 3

View File

@ -0,0 +1,3 @@
΄-΄Ή΄΄΄΄
΄΄΄0΄<EFBFBD>΄ <09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ο<EFBFBD><CE9F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><02><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ;΄΄΄΄΄<CE84><CE84><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>΄΄
΄΄΄<EFBFBD>΄΄

Some files were not shown because too many files have changed in this diff Show More