Skip to content

test(ethexe-malachite): corner case hunt#5491

Draft
grishasobol wants to merge 15 commits into
masterfrom
gsobol/ethexe/corner-case-hunt
Draft

test(ethexe-malachite): corner case hunt#5491
grishasobol wants to merge 15 commits into
masterfrom
gsobol/ethexe/corner-case-hunt

Conversation

@grishasobol

@grishasobol grishasobol commented May 21, 2026

Copy link
Copy Markdown
Member

To be investigated

@grishasobol grishasobol changed the title Gsobol/ethexe/corner case hunt test(ethexe): corner case hunt May 21, 2026
@grishasobol grishasobol self-assigned this May 21, 2026
@grishasobol grishasobol changed the title test(ethexe): corner case hunt test(ethexe-malachite): corner case hunt May 21, 2026
Base automatically changed from gsobol/ethexe/malachite-new to master May 25, 2026 16:59
grishasobol and others added 14 commits May 25, 2026 19:15
Seed log file for autonomous corner-case vulnerability hunt against the
malachite-new branch. Each iteration appends a row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mempool.insert accepts txs with reference_block_height > chain_head_height,
but consensus tx_validity (`is_reference_block_within_validity_window`)
explicitly rejects them. Such txs are unfetchable (future block is not on
`recent_ancestors`) AND occupy pool slots, enabling permanent capacity
exhaustion via a single signer pumping fake-future-anchored txs.

Test `insert_should_reject_future_ref_block` is `#[ignore]`d so CI stays
green; it documents the desired alignment with tx_validity.rs:184.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ompletion

`StreamState::insert` overwrites `total_messages` on every `Fin`, so a
second `Fin` at a lower sequence lowers the completion target. With
`buffer.len() == total_messages` as the gate, an attacker can force
premature completion of a proposal stream while genuine Data parts at
higher sequences are still missing. Marked `#[ignore]` so CI stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…wn-ref_block eviction race

mempool::insert tolerates a not-yet-replicated reference_block (best-effort,
filter-at-fetch-time), but purge_expired — invoked on every set_chain_head —
treats db.block_header(ref_block) == None as expired and evicts. The very next
block tick silently orphans every freshly-accepted tx whose ref_block hasn't
yet propagated locally, even though RPC already returned Accept to the client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Iteration 4 surfaced this as a "bug" but it's the same tradeoff already
documented in the fix for issue #9 (commit d52c62e): insert is
deliberately tolerant of unknown ref_block, and purge_expired drops on
next chain-head tick. SDK contract is ref_block <= head-1.

Add explicit row to Skip list so future iterations don't re-find it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…StreamState bug

StreamState::insert extracts the Init via `msg.is_first()` (= sequence == 0).
A Byzantine peer can place a Data part at sequence 0 and the actual Init at
sequence 1: init_info stays None forever, `is_done()` blocks on
init_info.is_some(), and the (peer, stream_id) slot is held even after all
parts + Fin arrive. Distinct from #5473 (general unboundedness) and from
iter#3's double-Fin attack.

Test is `#[ignore]`d so CI stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…oses 8x budget violation

validate_block_above lacks the cumulative encoded-size guard
build_block_above enforces (MAX_INJECTED_TRANSACTIONS_SIZE_PER_MB).
The validator only relies on Malachite's ~1 MiB block cap, which is
~8x the protocol's per-MB injected budget. A malicious proposer can
include injected txs totaling ~252 KiB and every validator accepts.

Test marked #[ignore]; tracks the gap until validate_block_above
mirrors the producer-side cap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… — exposes dedup bypass

forget() stamps committed txs into the seen table with their reference_block.
When that ref_block isn't yet in the local DB (lagging observer), the next
set_chain_head invokes purge_expired whose seen-retain loop drops unknown
ref_blocks — so the dedup gate disappears and the same network-committed
tx can be re-inserted. Symmetric to iter #4 but on the forget→purge path.
…xposes 1:1 amplification PartStreamsMap slot exhaustion
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…es 1-msg DoS

A peer-controlled `sequence == u64::MAX` triggers an overflow panic at
`streaming.rs:101` under the workspace dev profile (overflow-checks=on),
crashing the engine's app task. In release the same input wraps
`total_messages` to 0 and leaves the slot permanently parked. Test is
marked `#[ignore]`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pass

`mempool::insert` skips the `is_expired` check when `latest_head_height`
is `None` (cold-start window between node boot and first observer tick).
A post-fast-sync DB already holds block_headers so `ref_block_height`
resolves, but the expiry comparison never runs because the `&&` chain
short-circuits on the `None`. Public RPC therefore accepts expired txs
during the window; the very next `set_chain_head` then silently purges
them via `purge_expired`, leaving the client's promise to never fire.

Distinct from iter #2 (future-anchored ref_block, chain_head SET) and
iter #4 (unknown ref_block insert/purge tolerance mismatch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d — exposes validator accepting same signed injected tx twice in one MB

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@grishasobol
grishasobol force-pushed the gsobol/ethexe/corner-case-hunt branch from 91e03d1 to aabb34b Compare May 25, 2026 17:15
`cargo fmt` cleanup on two tests, plus exclude `corner-case-hunt-log.md`
from the typos lexicon — it carries lots of short git SHAs that the
checker can't tell from real words (e.g. `0ef199abd` → "abd"/"and").
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