Skip to content

types fuzzing#237

Open
abresas wants to merge 4 commits into
mainfrom
feat/types-fuzzing
Open

types fuzzing#237
abresas wants to merge 4 commits into
mainfrom
feat/types-fuzzing

Conversation

@abresas

@abresas abresas commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

No description provided.

abresas and others added 4 commits July 6, 2026 22:42
Two panics on valid API usage / untrusted input:

- MerkleTree::verify_multi_proof panicked (stack.remove(0) on an empty
  vec) on malformed proofs that pass the up-front count checks, e.g.
  leaves=[], flags=[false], path=[h1, h2]. Proofs arrive over RPC, so
  this was a remote DoS. Malformed shapes now return false.

- Receipt::generate_multi_proof_for_log_hashes panicked for any receipt
  with at least one log: join_prefix produced "log_hashes.[0]" while the
  tree was built with "log_hashes[0]", so the leaf lookup always failed
  and the expect() fired. Index segments now attach without a separator,
  consistent with index_prefix. No existing tree roots change: no
  current type produced dotted-index paths.

Both have regression tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
12 libFuzzer targets (nightly-only, own workspace under types/fuzz)
covering every encode/decode/parsing surface and the merkle tree:

- merkle_build_prove / merkle_proof_soundness / merkle_verify:
  build+prove round-trips, tampered/garbage proof rejection for both
  single proofs and multiproofs, and no-panic on fully adversarial
  proof material
- transaction_decode / transaction_roundtrip: decode_unsigned on raw
  bytes, and tagged + bare-legacy RLP encode/decode identity
- signed_tx_serde / signed_tx_deserialize: JSON + bincode round-trips
  with signer recovery, and garbage-bytes robustness
- receipt_serde: serde round-trips plus every log proof/multiproof
  verifying against the receipt root
- timestamp_parse, pagination_cursor, calldata_serde, log_filter_serde

CI runs a 15s smoke pass per target on nightly (fuzz.yml); longer
exploratory runs are documented in fuzz/README.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A floating nightly could break CI independent of repo changes. Pin to
the version the fuzz suite was developed against; cargo invocations use
the pinned default toolchain instead of +nightly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CallData asserted >= 4 bytes in new(), but serde deserialization never
enforced it and empty() violated it outright, so RPC/DB input could
produce values on which get_function_bytes()/get_body() panic.

Retype as { selector: [u8; 4], body: Bytes } so short calldata cannot
be constructed and the accessors are total. TryFrom<Bytes> is the
checked boundary for raw bytes (rejects < 4); serde goes through it.
The wire format is unchanged: hex string of selector ++ body for
human-readable formats, raw bytes otherwise.

Breaking: new() takes (selector, body); empty(), as_slice(), as_bytes()
are gone (to_bytes() returns the full blob). Nothing in the workspace
used them.

The calldata_serde fuzz target now exercises the accessors on every
value it can construct, including ones deserialized from garbage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant