SOME ONE IS STEALING MY CRYPTO#1
Open
caraabearzz wants to merge 2607 commits into
Open
Conversation
caraabearzz
commented
Jun 8, 2026
caraabearzz
left a comment
Owner
Author
There was a problem hiding this comment.
Looks like this was really good feedback. Thank you
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com>
* feat(symbolic): persist replayable counterexample artifacts * fix symbolic artifact replay semantics * fix sequence artifact replay result kind * fix sequence artifact replay revert count * fix symbolic artifact replay validation * fix(forge): validate symbolic replay senders * fix(forge): allow replay-created invariant targets * fix(forge): validate symbolic replay calls against ABI * fix(forge): respect selector filters in symbolic replay * fix(forge): reject zero sender in symbolic replay * fix(forge): report symbolic replay failure counts * fix: bless * fix(forge): validate symbolic replay sender * fix(forge): harden symbolic artifact replay * fix symbolic artifact replay path matching * fix invariant replay executed call counts * fix single-call symbolic artifact replay * strengthen symbolic artifact filename identity * tighten symbolic artifact replay validation --------- Co-authored-by: figtracer <me@figtracer.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com>
* perf(fuzz): avoid eager observed call calldata * fix(fuzz): make should_record_observed_call const Satisfies clippy::missing_const_for_fn (CI runs with -Dwarnings) and matches the surrounding const fn style. Amp-Thread-ID: https://ampcode.com/threads/T-019eeea2-e582-73e8-87c5-34c4dc836990 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com>
Switch the edge index lookup used during coverage merging to the map entry API and mark it inline. This keeps stable edge index assignment while avoiding a second map lookup when a new edge is assigned. Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com>
* perf(invariant): drain fuzzer values in place * refactor(fuzz): remove unused drain_collected_values The two invariant callsites now use InvariantFuzzState::collect_fuzzer_values, which drains in place and reuses the buffer allocation. drain_collected_values had no remaining callers and preserved the old allocation-dropping behavior, so remove it to avoid reintroducing the churn. Amp-Thread-ID: https://ampcode.com/threads/T-019eeea2-e582-73e8-87c5-34c4dc836990 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
* fix: add signed jwt bearer when used with --curl * fix collapsible_if * add JWT verification in tests * add shared helper to safely build jwt * run linter --------- Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com>
* feat(config): make isolate the default * Remove stale isolate-by-default feature references * test(forge): update isolate trace expectations * fix: address isolate default review comments * fix(bench): keep isolate benchmark modes explicit
* feat(lint): add tautological-compare detector Addresses #14381. A relational or equality comparison whose two sides are the same side-effect-free expression (x >= x, a[i] < a[i]) has a constant result, usually a typo or dead code. Flags it for idents, member access, and indexing; calls are excluded so sides that could differ are not flagged. * fix(lint): catch literal index self comparisons * fix(lint): skip user-defined operators in tautological-compare A user-defined value type can only be compared through a user-defined operator (`using {f as ==} for T global`), which dispatches to an arbitrary function rather than built-in equality, so `x == x` is not guaranteed to be constant. Skip operands whose type is a UDVT so the lint no longer flags these comparisons as tautological. * feat(lint): flag tautological self-comparison through identical casts * feat(lint): cover binary, unary, ternary and payable in tautological-compare --------- Co-authored-by: 0xMars42 <195151467+0xMars42@users.noreply.github.com> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com>
* perf(invariant): skip terminal corpus input generation * fix(invariant): handle empty corpus sequence after skipping terminal input Skipping terminal input generation removes the never-executed input that previously padded current_run.inputs. A run where every executed call is discarded (magic assume) or popped (reverts without fail_on_revert, handler assertions) can now leave an empty sequence while new_coverage is still set (edge coverage is collected before the input is popped), which hit assert!(!inputs.is_empty()) in process_inputs_inner. Replace the assert with explicit empty-sequence handling: still update mutation stats and optimization state, but return without persisting a corpus entry when no surviving inputs remain. Add a regression test for the empty-sequence path and document why next-input generation is conditional. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019eeea2-e582-73e8-87c5-34c4dc836990 * fix(invariant): preserve terminal input for optimization sequences --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
* perf(invariant): cache metric selector keys * fix(invariant): keep metric-key cache coherent with target set The metric-key cache keyed cached results (including None) as stable for the whole campaign. But invariant targets are updatable: newly deployed contracts are added via collect_created_contracts mid-run and cleared at end of run, and an address can be reused for a different artifact across runs. This made cached entries go stale and silently mis-record metrics. - Cache only resolved keys (no negative caching), so a tx whose target isn't a known target yet is re-resolved once the target is added. - Invalidate cached entries for addresses added by collect_created_contracts (mid-run reuse) and removed at end_run (cross-run reuse). Amp-Thread-ID: https://ampcode.com/threads/T-019eee95-59d3-76df-8984-f085cd504c65 Co-authored-by: Amp <amp@ampcode.com> * chore(invariant): fix clippy and trim comments - Make InvariantMetrics::record_call a const fn (missing_const_for_fn). - Shorten the metric-key cache comments. Amp-Thread-ID: https://ampcode.com/threads/T-019eee95-59d3-76df-8984-f085cd504c65 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
* perf(fuzz): avoid rebuilding storage layout map * perf(fuzz): remove now-unused get_storage_layouts The storage layout lookup is now done per-address directly against TargetedContracts, leaving get_storage_layouts with no callers. Remove it and its now-unused HashMap import. Amp-Thread-ID: https://ampcode.com/threads/T-019eee95-59d3-76df-8984-f085cd504c65 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com>
* minimize symbolic counterexamples * fix symbolic minimizer clippy * test symbolic minimizer echidna fixtures * test(symbolic): add echidna-derived minimizer fixtures * fix(symbolic): defer hard arithmetic branch unknowns * fix(symbolic): preserve minimizer failure identity * fix(symbolic): skip reasonless minimization * fix(symbolic): require minimizer replay reason
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz>
* fix(lint): include info rules by default * test(lint): use snapbox for default severity test * test(lint): bless default info snapshots
* fix(tempo): avoid receive-policy recipient collisions * fix(tempo): derive template recipient from token
* feat(forge): configure fuzzer ensemble defaults * chore(fuzz): tune corpus fresh sequence default * chore(fuzz): harden configurable corpus tuning * chore(fuzz): expose payable value weighting * chore(fuzz): use weighted mutation distribution * chore(fuzz): avoid default field reassignment * chore(invariant): clamp sampled run depth * fix(invariant): preserve fixed zero depth * test(invariant): stabilize handler assertion snapshot * fix(invariant): vary corpus freshness per worker * fix(invariant): tune corpus freshness ensemble * fix(invariant): satisfy worker config clippy * fix(forge): clamp invariant depth and validate mutation weights * test(forge): update zero-depth invariant snapshot * fix(forge): address fuzzer config review * fix(forge): preserve zero-depth and config provenance
* test: add T6 local regression coverage * test(tempo): use named T6 activation constants * test(tempo): cover T6 tempo-check flows
* feat(debugger): show failed-test debug hint * test(debugger): update invariant output snapshot
Reports a modifier that exactly one function invokes, constructors included. Invocations are taken from the resolved modifier lists, so base-constructor calls sitting in the same syntactic position are never confused with modifier calls; they are counted across the whole unit, dependencies included, while only modifiers declared in the project's own sources report, mirroring the unused-error pass. Exemptions: virtual modifiers and overrides, which exist for dynamic dispatch and cannot be inlined; zero invocations stay out, dead code being a different concern. Co-authored-by: 0xMars42 <195151467+0xMars42@users.noreply.github.com> Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com>
ci: detect Tempo hardfork in check script
…3342) * feat: init * chore: lexing/parsing * chore: visiting contracts * chore: wip * chore: wip * chore: wip * chore: visitor not visiting anything * chore: visitor visiting * chore: quick refactor before its too late * chore: quick refactor * chore: mutation gen part1 * feat: mutation collection * feat: visitor refactor * feat: visitor refactor * feat: temp folder mgmt * feat: temp file creation logic * feat: compiling mutants * chore: wip future multithread * feat: mutation set building * feat: multithread compile * chore: fmt * chore: fmt * chore: fmt * chore: fmt * feat: refactor for test runner * chore: test runner wip * feat: working poc * chore: doc * chore: fmt * chore: fmt * chore: fmt * feat: assign mut gen * feat: unary mut * feat: binary mut * feat: members unary mut * feat: members unary mut * feat: rm delegatecall mut * chore: refactor modular mut wip * chore: refactor modular mut wip * chore: refactor modular mut wip * feat: mutator assign trait * chore: fmt * chore: fmt * feat: bin mutator * feat: other mutator mod * feat: visitor refactor registry * chore: merge fix * chore: comment * fix: solar visitor use * chore: clippy and min refactors * feat: assign mutator tests * feat: test gen mut ident * feat: test binop and delete expr * feat: test delegate unaryop mut * feat: test unaryop mut * feat: wip generic test * refactor: add mutate-path and mutate-contract optional args, keep mutate args working like before * feat: enable contract match filter in mutation tests * feat: optional mutators * feat: generic mutator test(length) * feat: generic mutator test(content) * fix: unary mut for bool * test: unary mut * test: all mutators * test: add neg case * chore: refactor visitor * chore: clippy * chore: typos * feat: integ test (hacky) * feat: basic reporting * fix: copy only src * fix: copy only src * fix: rel path * fix: add walker in visitor * fix: assign mutator * chore: dbg cleanup * fix: dyn test linking * fix: missing mutant fmt * fix: path in mut ctxt * feat: save and resume mutation tests * chore: typo and doc * chore: remove cache file * merge master * clippy * update * use serde instead of manual dto for json caching checkpoint * fix cache filenames * initial pass at adaptive testing - skip surviving sibling or child spans * clippy && fmt * feat(forge): parallel mutation testing with isolated workspaces Implements parallel mutation testing for Foundry, building on PR #11996. Key features: - Parallel execution via rayon thread pool with configurable --mutation-jobs - Isolated TempDir workspaces per mutant for safe concurrent execution - Adaptive span skipping shared across workers (skip mutations in spans where a mutation already survived) - Fail-fast per mutant (stops on first test failure) - Symlinks for lib directories to avoid expensive copies - Preserves project layout (custom src/test/libs paths supported) Safety improvements: - Path traversal protection (rejects .. components) - catch_unwind prevents single panic from aborting entire run - Symlinked directories skipped in copy to prevent traversal attacks - 16MB stack size for rayon threads to avoid overflow Performance: 2.5x speedup observed with 4 workers on 150 mutants Closes #478 * fix: clippy, rustfmt, and config test for mutation_dir * feat(mutation): add progress display with Ctrl+C support - Add progress bar showing runs/total and job count - Show relative file paths instead of absolute paths - Add spinner for active mutants with line number and mutation diff - Capture original expression context in Mutant struct - Center code truncation around mutated operator - Graceful Ctrl+C: cancel pending, show report for completed, exit 130 - Enhanced reporter with Solidity diffs and security suggestions - Add mutation_testing_with_show_progress CLI test Amp-Thread-ID: https://ampcode.com/threads/T-019be5ee-0615-7048-97dc-7ba7b354d384 Co-authored-by: Amp <amp@ampcode.com> * chore: rename 'runs' to 'mutation runs' in progress bar * fix: mark doc code block as text to fix doctest * refactor: address grandizzy review comments - Move mutation logic from test/mod.rs to mutation/orchestrator.rs - Implement test helper for mutator tests - Add snapbox assertions to CLI mutation tests with full output - Update Solar LitKind comment (still valid - no int/uint distinction) - Use 4 workers in show-progress test for consistency Amp-Thread-ID: https://ampcode.com/threads/T-019be9ee-1c7c-734d-8e72-7e9b837b3945 Co-authored-by: Amp <amp@ampcode.com> * Add time and report legend * feat(mutation): add RequireMutator and source hash cache validation - Add RequireMutator for security-critical require/assert mutations - require(x) -> require(true) - always passes - require(x) -> require(false) - always fails - require(x) -> require(!x) - inverted condition - Add source content hash to SurvivedSpans cache - Prevents stale span reuse when source changes - Invalidates cache on hash mismatch - Handles legacy cache format migration - Add comprehensive integration test (mutation_testing_require_mutator) - Demonstrates two-phase testing workflow - First run: basic tests (84% score) - Second run: comprehensive tests (98.1% score) - Shows only equivalent mutant survives Amp-Thread-ID: https://ampcode.com/threads/T-019beb12-9720-740b-b4b6-de4f92eb10d6 Co-authored-by: Amp <amp@ampcode.com> * Add unary_op_mutator_test module to tests * fmt imports * Update crates/forge/src/mutation/mutators/mod.rs * nits * Update crates/forge/src/mutation/mutators/assignment_mutator.rs * nits * refactor: replace ctrlc with tokio signal, update rstest to 0.26 Addresses review comments from @zerosnacks: - Remove ctrlc dependency, use tokio's built-in signal handling instead - Update rstest from 0.25.0 to 0.26 - Add tokio signal feature for Ctrl+C handling The ctrlc crate is replaced with a background thread running a tokio runtime that waits on tokio::signal::ctrl_c(). This avoids adding the ctrlc dependency which is on the deny list. Amp-Thread-ID: https://ampcode.com/threads/T-019bec4d-844c-7624-9054-1b7e6b056c2c Co-authored-by: Amp <amp@ampcode.com> * feat(mutation): add --json support for mutation testing When --json flag is used with --mutate, outputs JSON with: - Summary: total, killed, survived, invalid, skipped, mutation_score, duration_secs - Survived mutants grouped by file with line, column, original expression, and mutant All progress messages are suppressed in JSON mode for clean output. Amp-Thread-ID: https://ampcode.com/threads/T-019bf8c4-8b62-741e-9226-e5cf23a050db Co-authored-by: Amp <amp@ampcode.com> * fix(mutation): symlink node_modules and soldeer dependencies in temp workspace (#13221) Projects using npm (node_modules/) or Soldeer (dependencies/) for external dependencies fail mutation testing because these directories are not copied to the temporary mutation workspace. This fix adds symlinking for these common external dependency directories, following the same pattern already used for lib directories. Fixes compilation errors like: error: 'node_modules/@uniswap/v3-core/...' not found Tested with: - Uniswap/universal-router (npm dependencies) - morpho-org/morpho-blue (lib dependencies) Amp-Thread-ID: https://ampcode.com/threads/T-019bf98e-1307-72f9-ac5f-a00d33518d40 Co-authored-by: Amp <amp@ampcode.com> * fix(mutation): recursively symlink nested lib directories in temp workspace (#13224) * fix(mutation): recursively symlink nested lib directories in temp workspace Projects with nested git submodules (e.g., lib/euler-earn/lib/openzeppelin-contracts) fail mutation testing because the temp workspace only symlinks top-level lib directories. When libraries have their own dependencies in nested lib/ folders, and remappings reference them with context-specific prefixes like: lib/euler-earn:@OpenZeppelin=lib/euler-earn/lib/openzeppelin-contracts/ These paths need to exist in the mutation workspace for compilation to succeed. This fix adds symlink_nested_libs() which recursively walks through each library and symlinks any nested lib/ directories, ensuring deeply nested submodules are accessible in the temp workspace. Tested against euler-xyz/evk-periphery which has multiple levels of nested submodules. Amp-Thread-ID: https://ampcode.com/threads/T-019bfa2f-d0b0-703a-9822-945c87b1e2ab Co-authored-by: Amp <amp@ampcode.com> * test(mutation): add unit tests for symlink and copy functions Tests cover: - symlink_dir: basic symlink creation - symlink_nested_libs: single level, deeply nested (3 levels), no lib dir, skip existing - copy_dir_recursive: basic copy, skip symlinked dirs, nonexistent source - relative_to_root: basic, same path, outside root Amp-Thread-ID: https://ampcode.com/threads/T-019bfa2f-d0b0-703a-9822-945c87b1e2ab Co-authored-by: Amp <amp@ampcode.com> * style: format with nightly rustfmt Amp-Thread-ID: https://ampcode.com/threads/T-019bfa2f-d0b0-703a-9822-945c87b1e2ab Co-authored-by: Amp <amp@ampcode.com> * fix(mutation): support custom lib directories in nested submodules Read each nested library's foundry.toml config to get its actual lib paths instead of hardcoding 'lib'. Falls back to default 'lib' if no config exists. Amp-Thread-ID: https://ampcode.com/threads/T-019bfab1-a4b5-7008-8fb4-735aa3a560ac Co-authored-by: Amp <amp@ampcode.com> * clippy fix --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: zerosnacks <zerosnacks@protonmail.com> * feat(mutation): add Yul opcode mutator (#13341) * feat: make mutation test operators configurable (#13410) make mutators configurable Amp-Thread-ID: https://ampcode.com/threads/T-019c477b-60f0-71af-853e-f2b5902f0906 Co-authored-by: Amp <amp@ampcode.com> * refactor: rename UnaryOperatorMutator to UnaryOpMutator (#13411) * make mutators configurable Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c477b-60f0-71af-853e-f2b5902f0906 * refactor: rename UnaryOperatorMutator to UnaryOpMutator Amp-Thread-ID: https://ampcode.com/threads/T-019c477b-60f0-71af-853e-f2b5902f0906 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> * fix: address mutation testing issues (#13412) * fix: address critical mutation testing issues - Rename orchestrator MutationConfig to MutationRunConfig to avoid naming collision with foundry_config::MutationConfig - Make generate_mutated_solidity and restore_original_source return Result instead of panicking, use byte-based splicing to avoid UTF-8 boundary panics - Validate relative paths in copy_project_for_mutation with is_safe_relative_path to prevent path escape when config paths are not under the project root - Fix cache key collisions by including a hash of the full contract path in cache filenames (prevents src/A.sol vs contracts/A.sol from sharing cache entries) - Make generate_ast return Result and propagate parse errors instead of silently swallowing them Amp-Thread-ID: https://ampcode.com/threads/T-019c477b-60f0-71af-853e-f2b5902f0906 Co-authored-by: Amp <amp@ampcode.com> * fix: harden mutation testing with path validation and diagnostics - Validate user-provided --mutate paths: normalize relative paths against config.root, check existence/is_file/.sol/non-test - Fix --mutate-contract to match any contract in a multi-contract file (use .any() instead of .find().is_some_and()) - Add span bounds check in generate_mutated_solidity to prevent panics on invalid span positions - Replace unwrap() with expect() in MutationContextBuilder calls with descriptive messages for each AST node type - Fix cross-platform relative_path: use Path::components() with forward-slash joining for stable output across OSes Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c47bc-5807-7721-9051-7028de802b89 * refactor: address review feedback for mutation testing Extract cache_file_path helper to consolidate repeated cache dir and filename prefix logic across persist/retrieve methods. Extract ensure_safe_relative_path helper to replace repeated validate-and-bail pattern for path safety checks. Remove dead code: generate_mutated_solidity and restore_original_source are unused (runner.rs uses its own apply_mutation with checked slicing and temp directories). Amp-Thread-ID: https://ampcode.com/threads/T-019c47ec-22ab-75db-9c35-35e0e08ac396 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> * chore: remove dead code from mutation module (#13413) * fix: address critical mutation testing issues - Rename orchestrator MutationConfig to MutationRunConfig to avoid naming collision with foundry_config::MutationConfig - Make generate_mutated_solidity and restore_original_source return Result instead of panicking, use byte-based splicing to avoid UTF-8 boundary panics - Validate relative paths in copy_project_for_mutation with is_safe_relative_path to prevent path escape when config paths are not under the project root - Fix cache key collisions by including a hash of the full contract path in cache filenames (prevents src/A.sol vs contracts/A.sol from sharing cache entries) - Make generate_ast return Result and propagate parse errors instead of silently swallowing them Amp-Thread-ID: https://ampcode.com/threads/T-019c477b-60f0-71af-853e-f2b5902f0906 Co-authored-by: Amp <amp@ampcode.com> * fix: harden mutation testing with path validation and diagnostics - Validate user-provided --mutate paths: normalize relative paths against config.root, check existence/is_file/.sol/non-test - Fix --mutate-contract to match any contract in a multi-contract file (use .any() instead of .find().is_some_and()) - Add span bounds check in generate_mutated_solidity to prevent panics on invalid span positions - Replace unwrap() with expect() in MutationContextBuilder calls with descriptive messages for each AST node type - Fix cross-platform relative_path: use Path::components() with forward-slash joining for stable output across OSes Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c47bc-5807-7721-9051-7028de802b89 * refactor: address review feedback for mutation testing Extract cache_file_path helper to consolidate repeated cache dir and filename prefix logic across persist/retrieve methods. Extract ensure_safe_relative_path helper to replace repeated validate-and-bail pattern for path safety checks. Remove dead code: generate_mutated_solidity and restore_original_source are unused (runner.rs uses its own apply_mutation with checked slicing and temp directories). Amp-Thread-ID: https://ampcode.com/threads/T-019c47ec-22ab-75db-9c35-35e0e08ac396 Co-authored-by: Amp <amp@ampcode.com> * chore: remove dead code from mutation module Remove unused symbols superseded by the orchestrator and parallel runner architecture: - MutationsSummary: update_valid_mutant, dead/survived/invalid/skipped string formatters, get_skipped, get_report_mut - Mutant: line_number(source) method (shadowed by field), format_diff, description_with_context - ParallelMutationRunner struct and run_mutations_parallel wrapper (replaced by orchestrator + run_mutations_parallel_with_progress) - Stale re-exports and unused imports Amp-Thread-ID: https://ampcode.com/threads/T-019c47ec-22ab-75db-9c35-35e0e08ac396 Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> * refactor(mutation): extract workspace utilities into shared module Move project-copying logic from mutation/runner.rs into a new crates/forge/src/workspace.rs module for reuse by other features that need isolated temp workspaces (e.g., brutalization). Extracted functions: copy_project, copy_dir_recursive, symlink_dir, symlink_nested_libs, relative_to_root, ensure_safe_relative_path. Tests moved from mutation/runner.rs to workspace.rs. Amp-Thread-ID: https://ampcode.com/threads/T-019c4d7b-acac-75ef-9f69-f3619f6941b6 Co-authored-by: Amp <amp@ampcode.com> * feat(mutation): add brutalizer mutator Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c2f6f-9824-74cc-a037-1bbcd139c9b5 * feat(mutation): add memory brutalization and FMP misalignment to brutalizer Extends the BrutalizerMutator to inject inline assembly at public/external function entry points, matching Solady's Brutalizer.sol modifier pattern. Memory brutalization dirties scratch space (0x00-0x3f) and memory beyond the free memory pointer, catching assembly that assumes zero-initialized memory. FMP misalignment adds a small deterministic odd offset (1-31 bytes) to the free memory pointer, catching assembly that assumes word-aligned pointers. Only applied to functions that contain inline assembly blocks, and only at call-frame boundaries (public/external) where the EVM guarantees fresh memory. Injecting into internal functions would overwrite legitimate caller state since internal calls share the call frame. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c2fc6-91f1-7202-b03e-4eb06c57f827 * refactor(mutation): restrict memory brutalization to external functions only Public functions can be called internally (JUMP, shared caller memory) or externally (CALL, fresh memory). At the source level we cannot distinguish which path will be taken, so brutalizing a public function risks overwriting legitimate caller state when called internally, producing false positives. External functions can only be entered via CALL/STATICCALL/DELEGATECALL, guaranteeing fresh zeroed memory. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c2fc6-91f1-7202-b03e-4eb06c57f827 * docs(mutation): improve brutalizer documentation Explain what the mutator tests (dirty bits in sub-256-bit types, memory safety assumptions), how to interpret mutation results (killed = code validates properly, survives = gap in coverage or bug), and the Solady equivalence. Document public function exclusion rationale. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c2fc6-91f1-7202-b03e-4eb06c57f827 * docs(mutation): document magic number functions in brutalizer Add doc comments explaining the injected assembly (what scratch space and FMP dirtying does), the splitmix64 constants (golden ratio, finalizer multiplier, avalanche shifts), and why FMP offsets are forced odd. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c2fc6-91f1-7202-b03e-4eb06c57f827 * fix: add missing column_number field, fix clippy lints Amp-Thread-ID: https://ampcode.com/threads/T-019c2ff5-b9f7-77b4-82a8-dd43d5eca9c3 Co-authored-by: Amp <amp@ampcode.com> * refactor(mutation): use span-derived random values for memory pollution Replace fixed not(0) pattern with deterministic random 256-bit words derived from the span position via splitmix64. Each mutation site now gets unique pollution values, catching bugs that might pass with all-1s but fail with other bit patterns. Extract shared splitmix64 and span_seed helpers, simplifying deterministic_mask and deterministic_fmp_offset. Amp-Thread-ID: https://ampcode.com/threads/T-019c2ff5-b9f7-77b4-82a8-dd43d5eca9c3 Co-authored-by: Amp <amp@ampcode.com> * perf(mutation): use keccak256 chain to fill 1KB past FMP Previously memory brutalization only wrote 2 words past the free memory pointer. Now writes a splitmix64-derived seed word at the FMP and chains keccak256 to fill 32 words (1024 bytes), catching assembly that reads uninitialized memory well beyond scratch space. Amp-Thread-ID: https://ampcode.com/threads/T-019c301f-203d-7282-9c23-580e91cf5be1 Co-authored-by: Amp <amp@ampcode.com> * refactor(mutation): split BrutalizerMutator into value, memory, and FMP mutators Split the monolithic BrutalizerMutator into three focused mutators: - BrutalizerValueMutator: XOR type casts to dirty unused bits - BrutalizerMemoryMutator: dirty scratch space and memory past FMP - BrutalizerFmpMutator: misalign free memory pointer Each has its own MutatorType variant (brutalizer-value, brutalizer-memory, brutalizer-fmp), all excluded by default. Shared helpers extracted to brutalizer_utils.rs. Amp-Thread-ID: https://ampcode.com/threads/T-019c4d59-fe83-7063-8690-7c1f6887c84b Co-authored-by: Amp <amp@ampcode.com> * refactor: extract brutalizer from mutation framework into standalone module - Move brutalizer logic out of mutation testing framework into crates/forge/src/brutalizer/ as a standalone source-level sanitizer - Remove BrutalizerValue, BrutalizerMemory, BrutalizerFmp mutators and their tests from the mutation framework - Create shared workspace module (crates/forge/src/workspace.rs) for project copying logic used by both mutation runner and brutalizer - Move workspace-related tests from mutation/runner.rs to workspace.rs - Add --brutalize flag to forge test with conflicts_with mutate - Make --brutalize and --mutate mutually exclusive via clap Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c4d7b-acac-75ef-9f69-f3619f6941b6 * fix: brutalizer value masks and temp config resolution - Fix value brutalizer to OR mask into discarded bits only (shift left by type width) instead of XORing the entire value, which corrupted kept bits and broke correct code under brutalization - Fix compile_and_run_brutalized to call .sanitized() on temp config so paths are absolute, fixing source file exclusion when filters (e.g. --mc) are active - Split brutalizer into sub-modules: value.rs, memory.rs, fmp.rs - Add 7 CLI integration tests for --brutalize Amp-Thread-ID: https://ampcode.com/threads/T-019c4d9e-9c66-723c-896e-65e641225266 Co-authored-by: Amp <amp@ampcode.com> * test: condense brutalizer tests, add mixed asm/solidity coverage, improve --brutalize help - Condense unit tests: merge special function exclusions and control flow variants into parameterized tests (27 → 20 tests) - Condense CLI tests: keep only high-impact tests (12 → 5 tests) - Add mixed Solidity/assembly patterns to robust contract: Solidity abi.encodePacked → assembly read, and assembly FMP alloc → Solidity - Update --brutalize help text to explain user-facing value: catches latent bugs from zero-initialized memory and clean register assumptions Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019c4d9e-9c66-723c-896e-65e641225266 * chore: clean-up imports * refactor: clean up brutalizer module layout * fix: avoid overlapping brutalizer cast transforms * fix: normalize brutalized casts * fix: preserve brutalize semantics and config * fix: rebase brutalize config paths * fix: rebase ignored compiler paths * fix: brutalize doesn't support `replay_symbolic_artifact` for now * fix: preserve brutalize rerun failures * fix: address brutalize review comments * fix(test): narrow brutalizer source rewrites Skip test, script, and library sources when brutalizing broad source roots, and fill complete scratch words so high-half scratch reads are dirtied. * test(forge): cover brutalized value bits * fix(forge): preserve brutalized write dirs Create project-local write-only fs permission directories in brutalized temp workspaces and canonicalize new write targets through their existing ancestor. * fix(forge): copy symlinked brutalize sources * fix(forge): persist brutalize rerun cache * fix(forge): preserve brutalize copy aliases * fix: via_ir warn * fix(forge): address brutalize review blockers --------- Co-authored-by: drgorillamd <83670532+drgorillamd@users.noreply.github.com> Co-authored-by: Simon Something /DrGoNoGo <83670532+simon-something@users.noreply.github.com> Co-authored-by: 0xchin <alanracciatti1220@gmail.com> Co-authored-by: emo.eth <emodoteth@gmail.com> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com> Co-authored-by: grandizzy <grandizzy.the.egg@gmail.com> Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com>
Compile local interface targets with ABI-only output and avoid writing artifacts for the command path. Benchmarked on a 3000-function/event/error Solidity fixture: - cold local source: 1.092s -> 326.6ms (3.34x faster) - after full build in prepare: 1.072s -> 321.1ms (3.34x faster) The generated interface output matched master byte-for-byte, fresh runs did not create the target artifact, and preexisting artifact bytes were preserved.
Compile forge doc through the Solar-oriented project path and disable artifact writes, since the doc renderer needs resolved HIR but not bytecode artifacts. Benchmarked on a 9006-line Solidity fixture with 3000 functions/events/errors: - cold forge doc: 1.101s -> 353.6ms (3.11x faster) - after full build in prepare: 1.106s -> 354.3ms (3.12x faster) Generated docs matched master byte-for-byte. Fresh doc generation did not create target artifacts, and a preexisting full artifact remained byte-for-byte unchanged.
* feat(forge): add coverage attribution report * fix(forge): respect report file for coverage attribution * fix(forge): order attribution coverage reports * perf(forge): reuse resolved coverage hit maps * docs(forge): document coverage attribution payloads * fix(forge): preserve attribution item anchors * fix(forge): dedupe coverage file reports * fix: DebugReporter anchor items filtering --------- Co-authored-by: smartcontracts <smartcontracts@users.noreply.github.com> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com> Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com>
* fix(cast): sort source output for deterministic diffs * fix(cast): make source output deterministic * bump foundry-core for deterministic cast source
Pass the assertion-failure result computed in the invariant worker into can_continue so the failure path does not rescan the same call result and state changeset. Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
* perf(invariant): use entry for sender changeset * chore: simplify sender changeset extraction --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
* perf(invariant): avoid eager block env clone * Update crates/evm/evm/src/executors/invariant/mod.rs --------- Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Check cheap call override rejection conditions before reading the handler set, then test caller and target membership under one read lock. This trims lock traffic on the invariant call override path without changing override eligibility. Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Move owned replay logs, debug bytecodes, and line coverage out of RawCallResult while preserving the existing trace ownership used for reports and counterexamples. Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Build invariant target contract and selector maps together, and use unstable sorting for sender address filters where sort stability is not observable. Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz>
Co-authored-by: autoopt[bot] <autoopt@tempo.xyz> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com> Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Solution
PR Checklist