feat(tokamak-debugger): Smart Contract Autopsy Lab + Sentinel Real-Time Detection#5
feat(tokamak-debugger): Smart Contract Autopsy Lab + Sentinel Real-Time Detection#5
Conversation
Complete Phase 0 analysis: evaluate ethrex, Reth, from-scratch, and revm-only options via weighted decision matrix. ethrex fork selected (score 4.85/5) for its custom LEVM, ZK-native architecture, Hook system, and manageable 133K-line codebase. Includes vision, competitive landscape, feature specs, team discussion summaries, Volkov review history, and branch strategy.
- Rebalance decision matrix to ethrex vs Reth binary comparison; move "from scratch" and "revm only" to appendix - Adjust Reth scores: ZK 1→2 (Zeth exists), manageability 2→3 (modular arch acknowledged), sync 5→4 for ethrex (less battle-tested) - Add EXIT criteria with 4 elements: metric, deadline, action, owner - Add Tier S PoC section: perf_opcode_timings build verification and code path analysis - Add JIT technical barriers (dynamic jumps, revmc reference) - Fix weighted sum arithmetic (Reth 2.85→2.80)
Record completed work: DECISION.md creation, Volkov R6 review (6.5/10), three mandatory fixes (matrix rebalance, EXIT criteria, Tier S PoC), Reth/Zeth/ExEx research findings, and next steps for Phase 1.1.
- DECISION.md: DRAFT → FINAL - Replace human staffing model with AI Agent development model - Add bus factor policy (Kevin as interim decision-maker) - Replace staffing risks with agent-specific risks - Remove Senior Rust 2명 EXIT criterion - Add 11 custom commands (.claude/commands/): - Development: /rust, /evm, /jit, /debugger, /l2 - Verification: /quality-gate, /safety-review, /diff-test - Operations: /rebase-upstream, /phase, /bench - Volkov R8: 7.5/10 PROCEED achieved
Architecture analysis documents: - OVERVIEW.md: 25+2 crate dependency graph, node startup flow, CI inventory - LEVM.md: VM struct, execution flow, dual-dispatch loop, hook system - MODIFICATION-POINTS.md: 5 modification points, hybrid isolation strategy - PHASE-1-1.md: Phase 1.1 execution plan with success criteria Phase 1.1 infrastructure: - Skeleton crates: tokamak-jit, tokamak-bench, tokamak-debugger - Feature flag: `tokamak` propagation chain (cmd → vm → levm) - Workspace registration for 3 new crates
- Fix OpcodeTimings: remove false min/max claim, document 4 actual fields - Fix CallFrame: caller→msg_sender, Bytes→Code, return_data→output/sub_return_data - Fix opcode table: describe const fn chaining pattern accurately - Label all pseudocode snippets consistently (JIT, debugger, L2 hook) - Plan feature flag split: tokamak → tokamak-jit/debugger/l2 - Add JIT-VM interface complexity analysis (5 challenges) - Add failure scenarios & mitigations table (5 scenarios) - Record build results: 5m53s clean, 718 tests passed - Fix line count ~133K → ~103K (verified via wc -l) - Add tokamak feature to OVERVIEW.md feature tables
Split monolithic `tokamak` feature into 3 independent features (tokamak-jit, tokamak-debugger, tokamak-l2) with umbrella re-export. Add pr-tokamak.yaml CI workflow for quality-gate and format checks. Update snapsync action default image to tokamak-network/ethrex. Document sync architecture, Hive test matrix, and success criteria.
Add structured benchmark infrastructure to tokamak-bench crate: - timings.rs: reset(), raw_totals(), raw_counts() accessors - tokamak-bench: types, runner, report, regression modules + CLI binary - CI workflow: pr-tokamak-bench.yaml (bench PR vs base, post comparison) - 11 unit tests covering regression detection, JSON roundtrip, reporting
Feature unification causes these modules to be compiled during L2 workspace clippy. Add targeted allows for arithmetic_side_effects, as_conversions, expect_used, and unsafe_code lints.
Add the core JIT tiered compilation modules that were missing from the branch: execution counter, code cache dispatch, types, and module declaration. These provide the lightweight in-process infrastructure gated behind the tokamak-jit feature flag.
- tokamak-jit: compiler, backend, adapter, validation, error modules - JIT backend CI job with LLVM 18 in pr-tokamak.yaml - jit_bench module in tokamak-bench for interpreter vs JIT comparison - Phase 2 architecture documentation - Updated HANDOFF with current status
Add Phase 3 JIT execution wiring so JIT-compiled bytecode actually runs through the VM dispatch instead of only being compiled. Key changes: - JitBackend trait in dispatch.rs for dependency inversion (LEVM defines interface, tokamak-jit implements) - LevmHost: revm Host v14.0 implementation backed by LEVM state (GeneralizedDatabase, Substate, Environment) - Execution bridge: builds revm Interpreter, wraps state in LevmHost, transmutes CompiledCode to EvmCompilerFn, maps result to JitOutcome - vm.rs wiring: try_jit_dispatch() && execute_jit() before interpreter loop, with fallback on failure - register_jit_backend() for startup registration - E2E tests: fibonacci JIT execution + JIT vs interpreter validation (behind revmc-backend feature, requires LLVM 21)
Close 7 gaps preventing production use of the JIT system: - 4A: Propagate is_static from CallFrame to revm Interpreter - 4B: Sync gas refunds after JIT execution, pass storage_original_values through JIT chain for correct SSTORE original vs present value - 4C: Add LRU eviction to CodeCache (VecDeque + max_entries) - 4D: Auto-compile when execution counter hits threshold, add compile() to JitBackend trait and backend() accessor to JitState - 4E: Detect CALL/CREATE/DELEGATECALL/STATICCALL opcodes in analyzer, skip JIT compilation for contracts with external calls - 4F: Skip JIT when tracer is active, add JitMetrics with atomic counters, log fallback events via eprintln
…compilation, and validation Phase 5 addresses three remaining JIT gaps: 5A — Multi-fork support: Cache key changed from H256 to (H256, Fork) so the same bytecode compiled at different forks gets separate cache entries. fork_to_spec_id() adapter added. Hardcoded SpecId::CANCUN removed from compiler, execution, and host — all now use the environment's fork. 5B — Background async compilation: New CompilerThread with std::sync::mpsc channel and a single background thread. On threshold hit, vm.rs tries request_compilation() first (non-blocking); falls back to synchronous compile if no thread is registered. register_jit_backend() now also starts the background compiler thread. 5C — Validation mode wiring: JitConfig.max_validation_runs (default 3) gates logging to first N executions per (hash, fork). JitState tracks validation_counts and logs [JIT-VALIDATE] with gas_used and output_len for offline comparison. Full dual-execution deferred to Phase 6.
M1: CompilerThread now implements Drop — drops sender to signal
shutdown, then joins the background thread. Panics are caught
and logged (no silent swallowing). Fields changed to Option
for take-on-drop pattern.
M2: SELFDESTRUCT (0xFF) added to has_external_calls detection in
analyzer.rs. Bytecodes containing SELFDESTRUCT are now skipped
by the JIT compiler, preventing the incomplete Host::selfdestruct
(missing balance transfer) from being exercised.
M3: Negative gas refund cast fixed in execution.rs. Previously
`refunded as u64` would wrap negative i64 (EIP-3529) to a huge
u64. Now uses `u64::try_from(refunded)` — negative values are
silently ignored (already reflected in gas remaining).
M4: Documented fork assumption in counter.rs and vm.rs. Counter is
keyed by bytecode hash only (not fork). Safe because forks don't
change during a node's runtime; cache miss on new fork falls back
to interpreter.
…ment Phase 6A — CALL/CREATE Resume: - Add JitResumeState, SubCallResult, JitSubCall types for suspend/resume - Add JitOutcome::Suspended variant for mid-execution suspension - Extend JitBackend trait with execute_resume for resume-after-subcall - Rewrite execution.rs: single-step execute, translate_frame_input, apply_subcall_result, handle_interpreter_action - Add resume loop in vm.rs JIT dispatch block - Add handle_jit_subcall() to execute sub-calls via LEVM interpreter - Add run_subcall() with depth-bounded interpreter loop - Remove has_external_calls compilation gate in backend.rs Phase 6B — LLVM Memory Management: - Add func_id: Option<u32> to CompiledCode for lifecycle tracking - Return evicted func_id from CodeCache::insert() on eviction - Add CompilerRequest enum (Compile/Free) to compiler_thread - Add send_free() method for cache eviction notifications - Wire Free request handling in register_jit_backend()
M1: Credit unused child gas back to revm interpreter via erase_cost()
M2: Write CALL output to interpreter memory at return_memory_offset
M3: Complete CREATE semantics (EIP-3860 initcode limit, nonce increment,
EIP-170 code size check, deploy code storage)
M4: Extract shared interpreter_loop(stop_depth) to eliminate opcode
dispatch table duplication between run_execution and run_subcall
M5: Add 7 tests for CALL/CREATE resume path (subcall.rs)
M6: Add balance validation before transfer in handle_jit_subcall
…daclass#6197) ## Motivation The L2 integration test (`test_erc20_roundtrip`) panics with `unwrap() on a None value` at `integration_tests.rs:705` after ~8 consecutive test runs against the same L1/L2 instance. The `find_withdrawal_with_widget` helper creates a fresh `L2ToL1MessagesTable` (starting from block 0), fetches all withdrawal logs, and searches for the latest withdrawal — but `on_tick` uses `truncate(50)` which keeps the **oldest** 50 items. After enough runs accumulate >50 withdrawal events, the newest withdrawal falls outside the window. The bug is not easily reproducible manually because `--dev` mode removes the databases on startup, so you can't restart with a pre-existing store that has >50 entries. It surfaces in CI when integration tests run repeatedly against the same L1/L2 instance without clearing state between runs. ## Description Replace `truncate(50)` with `drain(..len - 50)` in the `on_tick` methods so that the **newest** 50 messages are kept instead of the oldest. This fix is applied to all three monitor widgets that had the same pattern: - `L2ToL1MessagesTable` — withdrawal messages (original bug) - `L1ToL2MessagesTable` — deposit messages (same latent bug) - `BlocksTable` — block list (same latent bug) ## Checklist - [ ] Updated `STORE_SCHEMA_VERSION` (crates/storage/lib.rs) if the PR includes breaking changes to the `Store` requiring a re-sync.
R13 fixes (3.0 → 6.0): - M1: JIT CREATE tests exercising handle_jit_subcall CREATE arm - M2: EIP-7702 delegation gap documented with TODO comment - M3: Use from_bytecode_unchecked for CREATE init code - R1: Precompile value transfer test with identity precompile - R2: Non-precompile transfer guard aligned with generic_call - R3: Comment reference format unified (no line numbers) R14 fixes: - M1: JitState::reset_for_testing() with clear() on CodeCache, ExecutionCounter, JitMetrics for test isolation across #[serial] tests - M2: Differential JIT vs interpreter comparison in CREATE tests with jit_executions metrics assertion proving JIT path execution - M3: Remaining line number reference removed from vm.rs - R1: Precompile test strengthened with interpreter baseline comparison - R2: CREATE collision JIT test with pre-seeded address verification handle_jit_subcall CALL path: balance check, precompile BAL recording, value transfer with EIP-7708 log, non-precompile BAL checkpoint. handle_jit_subcall CREATE path: max nonce check, add_accessed_address, BAL recording, collision check, deploy nonce, EIP-7708 log.
Gate test-only methods (reset_for_testing, clear, reset) behind #[cfg(any(test, feature = "test-utils"))] to prevent production exposure. Add missing reset_for_testing() calls to remaining serial tests, gas_used differential assertions, and unit tests for new methods.
Reduce per-CALL overhead in JIT suspend/resume cycles without modifying revmc. Three runtime-level optimizations target DeFi router patterns (5-10 CALLs per tx): - Tier 1: Bytecode zero-copy — cache Arc<Bytes> in CompiledCode at compile time, use Arc::clone in execute_jit instead of Bytes::copy_from_slice (~1-5us/CALL saved) - Tier 2: Resume state pool — thread-local pool of JitResumeStateInner boxes (16-entry cap) eliminates Box alloc/dealloc per suspend/resume - Tier 3: TX-scoped bytecode cache — FxHashMap<H256, Code> on VM avoids repeated db.get_code() for same contract in multi-CALL transactions Adds bytecode_cache_hits metric to JitMetrics (9-tuple snapshot). 11 new tests in recursive_call_opt.rs, 69 total tokamak-jit tests.
…ifetime erasure
EvmCompiler contains raw LLVM pointers that aren't Send. Remove the
+ Send bound from ArenaCompiler.compilers since it only lives in
thread_local! storage. Add explicit lifetime transmute ('ctx -> 'static)
with safety comment. Also fix HashMap import scope and remove unused
JitBackend import.
Add KeccakLoop (chained hashing, 2.50x), BitwiseOps (XOR/AND/OR/SHL/SHR, 3.50x), and Exponentiation (MULMOD/ADDMOD, 2.19x). All bytecodes are under 24KB (226-257 bytes), making them JIT-compilable. Includes Solidity sources and solc-compiled bin-runtime files.
…tests - fibonacci: add INTRINSIC_GAS import, use 20% tolerance for JIT vs interpreter gas comparison (EIP-2929 access list pre-warming causes small gas discrepancy between direct execute_jit and full VM paths) - oversized: remove unused mut on db variable
- group-ib-analysis.md: product ideas from Group-IB Crime Trends 2026 - volkov-derived-ideas.md: 5 service ideas from internal Volkov Review - autopsy-lab-plan.md: detailed implementation plan for hack post-mortem analysis service using existing Time-Travel Debugger infrastructure
Post-hack analysis service built on the Time-Travel Debugger: - RemoteVmDatabase: archive node RPC client + LEVM Database impl with caching - StepRecord enrichment: CALL value, LOG topics, SSTORE capture in recorder - AttackClassifier: reentrancy, flash loan, price manipulation, access control detection - FundFlowTracer: ETH transfers + ERC-20 Transfer event tracking - AutopsyReport: JSON + Markdown output with suggested fixes - CLI: `autopsy --tx-hash <HASH> --rpc-url <URL>` subcommand New `autopsy` feature flag gates reqwest/sha3/serde_json/rustc-hash deps. Tests: 28 base + 42 autopsy + 27 cli = 97 total (was 55).
… and all sections - Add ExecutionOverview with call depth, opcode stats, contract count - Always show all report sections (empty ones show "None detected") - Fix legacy/EIP-1559 TX type auto-detection in CLI - Set gas_price, tx_max_fee_per_gas, tx_nonce in Environment - Use TX gas limit (not block) for Environment.gas_limit
Reports are now saved to a file instead of printing to stdout. Default
filename is autopsy-{hash_prefix}.{ext} in the current directory.
…callback patterns Three detection strategies: 1. ETH value: existing CALL value borrow/repay matching 2. ERC-20: matching Transfer events (same token, to/from same address) 3. Callback depth: >60% of ops at depth > entry+1 indicates flash loan callback Tested on Euler Finance stETH exploit TX — correctly identifies flash loan provider (Lido stETH) and borrow/repay steps (257→9966 of 9991 total). 100 tests (was 97).
Address 9 issues from /devil review (6.8→target 8.5/10):
- Verdict-first summary ("VERDICT: Flash Loan detected.")
- Known contract labels (~20 mainnet addresses: DAI, WETH, Lido, Aave)
- PUSHn/DUPn/SWAPn aggregated in top opcodes (no duplicates)
- Zero-amount flash loans show "amount unknown" instead of "0 wei"
- All affected contracts listed with Role column (was 3/9, now 9/9)
- Storage value interpretation (MAX_UINT256, 0→nonzero, etc.)
- Section transition text for narrative flow
- Protocol-specific suggested fixes with disclaimer
- Conclusion section with attack timeline and callback span %
W1: Add Fund Flow limitation note (callback amounts not captured) W2: Provider → "Suspected provider (heuristic)" throughout report W2: Add "Unlabeled contracts" footer to Affected Contracts table W3: Truncate storage slot hashes (0xabcdef01…89abcdef) + ABI footnote W3: ERC-20 zero-value transfers show "(undecoded)" instead of "0" W4: Uniform table separators (--- for all columns) W5: Key Steps expanded — SSTORE, CREATE, ERC-20 events (2→7 entries) W5: Conclusion replaces timeline copy with storage impact analysis
- E-4 (Smart Contract Autopsy Lab): mark as complete in ROADMAP + STATUS
- RemoteVmDatabase, AttackClassifier (4 patterns), FundFlowTracer,
AutopsyReport (verdict-first MD/JSON), CLI subcommand, 100 tests
- Phase H (Real-Time Attack Detection — Sentinel): new 5-task roadmap
- H-1: Block execution recording hook
- H-2: Lightweight pre-filter (depth/gas/calls/watchlist)
- H-3: Real-time classification pipeline (async producer-consumer)
- H-4: Alert & notification system (webhook/Slack/log)
- H-5: Sentinel dashboard (WebSocket + historical browsing)
- STATUS: update Feature #21 (85%→95%), add Feature #22 (0%)
…provements Phase I — Network Resilience: - RPC timeout (30s) + exponential backoff retry (3 retries, 1s→2s→4s) - Structured RpcError enum (6 variants) with retryable classification - RpcConfig struct with --rpc-timeout/--rpc-retries CLI flags Phase II — Data Quality: - ERC-20 transfer amount decoding from LOG3 data bytes - Price delta estimation via SLOAD value comparison - 80+ known mainnet contract labels (DEX, lending, bridges, oracles) - ABI-based storage slot decoding (keccak256 mapping support) Phase III — Robustness: - Bounded caches with FIFO eviction in RemoteVmDatabase - AutopsyMetrics observability (RPC calls, cache hits, latency) - 100k-step stress tests (<5s classification, <1s report) Phase IV — Validation & Confidence: - DetectedPattern wrapper with 0.0-1.0 confidence + evidence chains - 10 mainnet exploit validation scaffolds (DAO, Euler, Curve, etc.) Cross-crate: OpcodeRecorder::record_step now takes &Memory for LOG data capture. Memory::current_base_offset() added to LEVM. Tests: 145 passing + 10 ignored mainnet scaffolds (was 97).
Remove JIT compiler (tokamak-jit), benchmark harness (tokamak-bench), dashboard, LEVM JIT module, L2 scaffolding, and related CI/docs from the autopsy branch. These features live on feat/tokamak-three-pillars. Add Phase H Sentinel real-time attack detection plan (SENTINEL-PLAN.md).
…H-3) Implement the Sentinel system — a real-time hack detection pipeline that monitors committed blocks for suspicious transactions and generates alerts. Phase H-1: Pre-Filter Engine - 7 receipt-based heuristics (flash loan signature, high-value revert, multiple ERC-20 transfers, known contract interaction, unusual gas, self-destruct indicators, oracle+swap pattern) - SentinelConfig with configurable thresholds, 14 known mainnet addresses - `sentinel` feature flag in tokamak-debugger - 32 tests Phase H-2: Deep Analysis Engine - replay_tx_from_store: re-executes suspicious TX from local Store with OpcodeRecorder, executing preceding TXs to reconstruct correct state - DeepAnalyzer: orchestrates replay → AttackClassifier → FundFlowTracer (reuses E-4 autopsy infrastructure via #[cfg(feature = "autopsy")]) - SentinelAlert, SentinelError (8 variants), AnalysisConfig types - 20 tests (14 sentinel-only + 6 autopsy-gated) Phase H-3: Block Processing Integration - BlockObserver trait in ethrex-blockchain (DIP — avoids circular dep) - SentinelService: background worker thread with mpsc channel, two-stage PreFilter → DeepAnalyzer pipeline, non-blocking on block processing - Hooks in add_block/add_block_pipeline after store_block - AlertHandler trait + LogAlertHandler default implementation - Graceful shutdown via Drop (send signal + join worker thread) - 11 tests Architecture doc: docs/tokamak/SENTINEL-ARCHITECTURE.md Total: 208 passing + 10 ignored, clippy clean all feature combinations.
…nd metrics (H-4/H-5) H-4 Alert & Notification System: - AlertDispatcher composite fan-out to multiple handlers - JsonlFileAlertHandler (append-only JSONL), StdoutAlertHandler - WebhookAlertHandler (HTTP POST + exponential backoff, autopsy-gated) - AlertDeduplicator (block-window suppression), AlertRateLimiter (sliding-window) H-5 Sentinel Dashboard: - WsAlertBroadcaster: real-time WebSocket alert feed with dead-subscriber cleanup - AlertHistory: JSONL-based query engine with pagination, filtering, sorting - SentinelMetrics: Prometheus text exposition format (8 atomic counters) - Dashboard UI: Astro+React sentinel page with AlertFeed, AlertCard, AlertHistoryTable, SentinelMetricsPanel components - SentinelService instrumented with timing and counter metrics Tests: 259 Rust (cli+autopsy+sentinel) + 97 dashboard, clippy clean
…mode Add prefilter_alert_mode to AnalysisConfig for lightweight monitoring without full Merkle trie state. When enabled, SentinelService emits PreFilter-based alerts if deep analysis fails or returns nothing. Three E2E tests prove the full pipeline: bytecode execution through LEVM with opcode recording, AttackClassifier reentrancy detection (confidence >= 0.7), PreFilter receipt-based heuristics, and SentinelService background worker alert emission. 262 tests pass (+3 new), 10 ignored, clippy clean.
…2E test 6-phase E2E test with real bytecode execution through the entire Sentinel pipeline (LEVM → AttackClassifier → FundFlowTracer → SentinelService → alert validation). Also adds an executable demo example that visualizes each phase. - Phase 1: Deploy attacker+victim contracts, execute in LEVM (80 steps) - Phase 2: Verify call depth >= 3 and SSTORE count >= 2 - Phase 3: AttackClassifier detects Reentrancy (confidence >= 70%) - Phase 4: FundFlowTracer traces ETH transfers (victim → attacker) - Phase 5: SentinelService processes real receipt, emits alert - Phase 6: Validate alert content and metrics counters Test count: 263 passing + 10 ignored (was 262+10), clippy clean.
- Add live reentrancy pipeline entry to Feature #21 and Phase H sections - Update tokamak-debugger file/line counts (33→45 files, ~6,950→~13,900 lines) - Update total Tokamak codebase count (~16,630→~23,980 lines) - Test count: 263 passing + 10 ignored
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly expands the Tokamak debugger's capabilities by introducing a comprehensive Smart Contract Autopsy Lab for forensic analysis and a Sentinel system for real-time attack detection. These new features are supported by robust infrastructure improvements, including enhanced RPC and P2P communication, optimized block processing, and detailed developer documentation. The changes aim to provide powerful tools for understanding and mitigating smart contract vulnerabilities, both reactively and proactively. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This is an impressive and substantial feature addition, introducing the Smart Contract Autopsy Lab and Sentinel real-time detection system. The changes are extensive, touching everything from the core blockchain logic and networking to the CI/CD pipeline, and introducing the comprehensive tokamak-debugger crate. The architectural changes, such as the BlockObserver trait for Sentinel integration and the highly parallelized state merkleization using Block Access Lists, are well-designed. The performance and robustness improvements, including the fast-path interpreter loop, precompile caching, and the enhanced proof coordinator logic, are excellent. My review focuses on a couple of opportunities to improve maintainability by reducing code duplication and simplifying some logic.
| // Clone block + receipts for observer before store_block consumes them | ||
| let observer_data = self | ||
| .block_observer | ||
| .as_ref() | ||
| .map(|_| (block.clone(), res.receipts.clone())); | ||
|
|
||
| let merkleized = Instant::now(); | ||
| let result = self.store_block(block, account_updates_list, res); | ||
| let stored = Instant::now(); | ||
|
|
||
| // Notify observer after successful store | ||
| if result.is_ok() | ||
| && let Some((block_clone, receipts)) = observer_data | ||
| && let Some(observer) = &self.block_observer | ||
| { | ||
| observer.on_block_committed(block_clone, receipts); | ||
| } |
There was a problem hiding this comment.
This block of code for notifying the block_observer is duplicated in add_block_pipeline (lines 2034-2050). To improve maintainability and reduce redundancy, consider refactoring this logic into a private helper method.
For example, you could create a method like notify_observer(&self, block: &Block, receipts: &[Receipt]) that you can call from both places.
| let risc0_bytes = proofs | ||
| .get(&ProverType::RISC0) | ||
| .map(|proof| proof.calldata()) | ||
| .unwrap_or(ProverType::RISC0.empty_calldata()) | ||
| .as_slice(), | ||
| proofs | ||
| .into_iter() | ||
| .next() | ||
| .unwrap_or(Value::Bytes(vec![].into())); | ||
| risc0_array.push(risc0_bytes); | ||
|
|
||
| let sp1_bytes = proofs | ||
| .get(&ProverType::SP1) | ||
| .map(|proof| proof.calldata()) | ||
| .unwrap_or(ProverType::SP1.empty_calldata()) | ||
| .as_slice(), | ||
| proofs | ||
| .into_iter() | ||
| .next() | ||
| .unwrap_or(Value::Bytes(vec![].into())); | ||
| sp1_array.push(sp1_bytes); | ||
|
|
||
| let tdx_bytes = proofs | ||
| .get(&ProverType::TDX) | ||
| .map(|proof| proof.calldata()) | ||
| .unwrap_or(ProverType::TDX.empty_calldata()) | ||
| .as_slice(), | ||
| ] | ||
| .concat(); | ||
| .into_iter() | ||
| .next() | ||
| .unwrap_or(Value::Bytes(vec![].into())); | ||
| tdx_array.push(tdx_bytes); | ||
| } |
There was a problem hiding this comment.
The logic to extract the calldata bytes for each prover type is a bit complex and could be simplified for better readability and robustness. The chain of map, unwrap_or, into_iter, next, and another unwrap_or is hard to follow.
You could simplify this by using and_then and unwrap_or_else for a more direct approach. This would make the intent clearer and reduce the chance of panics if the behavior of empty_calldata() were to change in the future.
| let risc0_bytes = proofs | |
| .get(&ProverType::RISC0) | |
| .map(|proof| proof.calldata()) | |
| .unwrap_or(ProverType::RISC0.empty_calldata()) | |
| .as_slice(), | |
| proofs | |
| .into_iter() | |
| .next() | |
| .unwrap_or(Value::Bytes(vec![].into())); | |
| risc0_array.push(risc0_bytes); | |
| let sp1_bytes = proofs | |
| .get(&ProverType::SP1) | |
| .map(|proof| proof.calldata()) | |
| .unwrap_or(ProverType::SP1.empty_calldata()) | |
| .as_slice(), | |
| proofs | |
| .into_iter() | |
| .next() | |
| .unwrap_or(Value::Bytes(vec![].into())); | |
| sp1_array.push(sp1_bytes); | |
| let tdx_bytes = proofs | |
| .get(&ProverType::TDX) | |
| .map(|proof| proof.calldata()) | |
| .unwrap_or(ProverType::TDX.empty_calldata()) | |
| .as_slice(), | |
| ] | |
| .concat(); | |
| .into_iter() | |
| .next() | |
| .unwrap_or(Value::Bytes(vec![].into())); | |
| tdx_array.push(tdx_bytes); | |
| } | |
| let risc0_bytes = proofs.get(&ProverType::RISC0) | |
| .and_then(|p| p.calldata().into_iter().next()) | |
| .unwrap_or_else(|| Value::Bytes(Default::default())); | |
| risc0_array.push(risc0_bytes); | |
| let sp1_bytes = proofs.get(&ProverType::SP1) | |
| .and_then(|p| p.calldata().into_iter().next()) | |
| .unwrap_or_else(|| Value::Bytes(Default::default())); | |
| sp1_array.push(sp1_bytes); | |
| let tdx_bytes = proofs.get(&ProverType::TDX) | |
| .and_then(|p| p.calldata().into_iter().next()) | |
| .unwrap_or_else(|| Value::Bytes(Default::default())); | |
| tdx_array.push(tdx_bytes); |
Benchmark Results ComparisonNo significant difference was registered for any benchmark run. Detailed ResultsBenchmark Results: BubbleSort
Benchmark Results: ERC20Approval
Benchmark Results: ERC20Mint
Benchmark Results: ERC20Transfer
Benchmark Results: Factorial
Benchmark Results: FactorialRecursive
Benchmark Results: Fibonacci
Benchmark Results: FibonacciRecursive
Benchmark Results: ManyHashes
Benchmark Results: MstoreBench
Benchmark Results: Push
Benchmark Results: SstoreBench_no_opt
|
|
@cd4761 Please change the base branch of this PR from |
…ptive pipeline, and auto-pause Expand the Sentinel real-time attack detection system with four H-6 sub-features, plus security hardening from code review: H-6a (CLI & Configuration): - TOML SentinelFullConfig with 6 sub-configs (sentinel, analysis, alert, dedup, rate-limit, auto-pause) - load_config/merge_cli_overrides/validate functions - 6 --sentinel.* CLI flags in ethrex cmd - init_sentinel() bootstrap returning SentinelComponents H-6b (Mempool Monitoring): - MempoolPreFilter with 5 calldata heuristics (flash-loan selector, high-value DeFi, high-gas known contract, suspicious creation, multicall pattern) - MempoolObserver trait in ethrex-blockchain with hooks in add_transaction_to_pool/add_blob_transaction_to_pool - MempoolAlert/MempoolSuspicionReason types H-6c (Adaptive Pipeline): - AnalysisStep trait + StepResult (Continue/Dismiss/AddSteps) - FeatureVector (16 numerical features) - 6 pipeline steps (FlashLoan/Reentrancy/PriceManip/AccessControl/ FundFlow/AnomalyDetection) - StatisticalAnomalyDetector (z-score + sigmoid confidence) - AnalysisPipeline orchestrator with PipelineMetrics H-6d (Auto Pause): - PauseController (AtomicBool + Condvar + auto-resume timer) in ethrex-blockchain with check_pause() in add_block - AutoPauseHandler (AlertHandler circuit breaker with configurable score threshold) - sentinel_resume/sentinel_status JSON-RPC endpoints Security fixes from code review: - Move sentinel_resume to authrpc-only (was exposed on public HTTP) - Bound dynamic pipeline step queue to MAX_DYNAMIC_STEPS=64 - Use combined confidence score (max of prefilter, pipeline) in alerts - PauseController fail-open on lock poisoning (log + unpause, no panic) Tests: 310 passing + 10 ignored (debugger), 5 passing (PauseController) Clippy: clean on tokamak-debugger, ethrex-blockchain, ethrex (default)
Add sentinel_dashboard_demo.rs — a mini HTTP+WS server (Axum on port 3001)
that serves the 3 endpoints expected by the Astro+React dashboard:
- GET /sentinel/metrics — 4-field JSON metrics snapshot
- GET /sentinel/history — paginated alert history with filters
- GET /sentinel/ws — WebSocket real-time alert feed
Key design:
- SuspicionReason remapping from Rust externally-tagged enum to
dashboard's {type, details} format
- AlertQueryResult field mapping (total_count → total)
- Background block generator (3s cycle, 3 TX patterns)
- CORS permissive for cross-origin dashboard access
- axum(ws), tower-http(cors), tokio(full) added to sentinel feature
9a7fe47 to
03fc185
Compare
…ntainability - CORS: restrict origin to Tauri dev/prod allowlist (Copilot #1) - open-url: use execFile with arg arrays instead of shell exec (Copilot #2) - fs browse: restrict path traversal to home directory (Copilot #3) - test-e2e-fork: move RPC URL to SEPOLIA_RPC_URL env var (Copilot #4) - docker-remote: clear timeout on stream close, close stream on timeout (Copilot #5) - docker-remote: add shell quoting (q()) and assertSafeName for all interpolated shell args to prevent injection (Copilot #6-8) - genesis.rs: add ChainConfig::validate() for pre-startup checks (Copilot #9) - listings.js: use named params (@id, @name, ...) instead of 30 positional ? args for upsertListing (Gemini #1)
- Return 503 instead of {exists:false} on check endpoint errors (#1)
- Sanitize all error messages — log internally, return generic to client (#2,#3,#4,#5)
- Add serverless rate limit limitation comment (#6)
- Add console.warn to all empty catch blocks in github-pr.ts (#9,#10,#11)
- Note: params as Promise is correct for Next.js 15 (#7,#8)
* feat(platform): add appchain registry API routes to Next.js client Port Express server appchain-registry endpoints to Next.js API routes for Vercel deployment: - GET /api/appchain-registry/check/[l1ChainId]/[stackType]/[identityAddress] - POST /api/appchain-registry/submit - GET /api/appchain-registry/status/[prNumber] Shared logic in lib/appchain-registry.ts and lib/github-pr.ts. * fix: address PR #67 code review feedback - Return 503 instead of {exists:false} on check endpoint errors (#1) - Sanitize all error messages — log internally, return generic to client (#2,#3,#4,#5) - Add serverless rate limit limitation comment (#6) - Add console.warn to all empty catch blocks in github-pr.ts (#9,#10,#11) - Note: params as Promise is correct for Next.js 15 (#7,#8) * fix: address additional Copilot PR #67 review feedback - Add AbortSignal.timeout(15s) to all GitHub API fetch calls - Fix authHeaders error message to list both accepted env vars - Distinguish RPC errors (502) from permission denied (403) in ownership check - Add typeof validation for metadata.signedBy - Add unit test suggestion acknowledged (future work)
Summary
H-6 Expansion Details
H-6a: CLI & Configuration
SentinelFullConfigwith 6 sub-configsload_config/merge_cli_overrides/validatefunctions--sentinel.*CLI flags wired into ethrex cmdinit_sentinel()bootstrap returningSentinelComponentsH-6b: Mempool Monitoring
MempoolPreFilterwith 5 calldata heuristics (flash-loan selector, high-value DeFi, high-gas known contract, suspicious creation, multicall pattern)MempoolObservertrait in ethrex-blockchain with hooks inadd_transaction_to_pool/add_blob_transaction_to_poolMempoolAlert/MempoolSuspicionReasontypesH-6c: Adaptive Pipeline
AnalysisSteptrait +StepResult(Continue/Dismiss/AddSteps)FeatureVectorwith 16 numerical featuresStatisticalAnomalyDetector(z-score + sigmoid confidence)AnalysisPipelineorchestrator withPipelineMetricsH-6d: Auto Pause
PauseController(AtomicBool + Condvar + auto-resume timer) in ethrex-blockchainAutoPauseHandler(AlertHandler circuit breaker with configurable score threshold)sentinel_resume/sentinel_statusJSON-RPC endpoints (authrpc-only for resume)Security Hardening (Code Review)
sentinel_resumemoved to authrpc-only (was exposed on public HTTP)MAX_DYNAMIC_STEPS = 64max(prefilter, pipeline)) in alertsPauseControllerfail-open on lock poisoning (no panic)Test Plan
cargo test -p tokamak-debugger— 28 base testscargo test -p tokamak-debugger --features sentinel— 184 testscargo test -p tokamak-debugger --features autopsy— 118 + 10 ignoredcargo test -p tokamak-debugger --features "sentinel,autopsy"— 283 + 10 ignoredcargo test -p tokamak-debugger --features "cli,autopsy,sentinel"— 310 + 10 ignoredcargo test -p ethrex-blockchain pause_controller— 5 testscargo clippy -p tokamak-debugger --features "cli,autopsy,sentinel"— cleancargo clippy -p ethrex-blockchain— cleancargo build(default features) — clean