From f623446996bbfed894c213e728bae46a2eea028a Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 13:36:11 +0000 Subject: [PATCH 1/6] ci: unified frontend workflow (lint + typecheck + build) --- .github/workflows/ci.yml | 58 ++++++++++++++++++++++++++++++++++++++ .github/workflows/lint.yml | 24 ---------------- frontend/package.json | 3 +- 3 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7a41dd8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ~/.cache/biome + key: biome-${{ runner.os }}-${{ hashFiles('biome.json') }} + restore-keys: biome-${{ runner.os }}- + - uses: biomejs/setup-biome@v2 + with: + version: 2.1.2 + - run: biome ci --linter-enabled=true --formatter-enabled=true + + typecheck: + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: frontend/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm typecheck + + build: + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: frontend/pnpm-lock.yaml + - run: pnpm install --frozen-lockfile + - run: pnpm build diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index a45e8ad..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Lint - -on: - pull_request: - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Cache Biome - uses: actions/cache@v4 - with: - path: ~/.cache/biome - key: biome-${{ runner.os }}-${{ hashFiles('biome.json') }} - restore-keys: | - biome-${{ runner.os }}- - - name: Setup Biome - uses: biomejs/setup-biome@v2 - with: - version: 2.1.2 - - name: Run Biome - run: biome ci --linter-enabled=true --formatter-enabled=true diff --git a/frontend/package.json b/frontend/package.json index e514025..5367bdc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "typecheck": "tsc --noEmit" }, "dependencies": { "@number-flow/react": "0.5.10", From 474b5ed3feb78355c53bb973d96dc04d6ad53647 Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:05:31 +0000 Subject: [PATCH 2/6] ci: add rust job (fmt + clippy + build) --- .github/workflows/ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a41dd8..9bd3d54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,3 +56,19 @@ jobs: cache-dependency-path: frontend/pnpm-lock.yaml - run: pnpm install --frozen-lockfile - run: pnpm build + + rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake pkg-config libssl-dev libclang-dev libzstd-dev libhugetlbfs-dev + - uses: dtolnay/rust-toolchain@1.91.0 + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo fmt --all --check + - run: cargo clippy --all-targets --all-features -- -D warnings + - run: cargo build --all-targets From bf98b5d0b145a7d403921f20831f685e4e0b9c8c Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:08:17 +0000 Subject: [PATCH 3/6] ci: run rust job in rust:1.91-slim container for libclang/bindgen parity --- .github/workflows/ci.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bd3d54..6033a68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,15 +59,16 @@ jobs: rust: runs-on: ubuntu-latest + # Match the backend Dockerfile's build image so bindgen sees a libclang + # new enough for the upstream C23 (`constexpr`) headers from monad-bft. + container: rust:1.91-slim steps: - - uses: actions/checkout@v4 - - name: Install system dependencies + - name: Install build dependencies run: | - sudo apt-get update - sudo apt-get install -y cmake pkg-config libssl-dev libclang-dev libzstd-dev libhugetlbfs-dev - - uses: dtolnay/rust-toolchain@1.91.0 - with: - components: rustfmt, clippy + apt-get update + apt-get install -y git curl gcc g++ cmake pkg-config libssl-dev libclang-dev libzstd-dev libhugetlbfs-dev + - uses: actions/checkout@v4 + - run: rustup component add rustfmt clippy - uses: Swatinem/rust-cache@v2 - run: cargo fmt --all --check - run: cargo clippy --all-targets --all-features -- -D warnings From e827de0bddeab5779601d1d774f4e3531cda6eda Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 14:16:27 +0000 Subject: [PATCH 4/6] fix(backend): resolve auto-fixable clippy lints Addresses 6 of the 8 clippy findings surfaced by the new rust CI job: - needless_return (server.rs) - match_like_matches_macro (server.rs) - ptr_arg: &Vec -> &[T] (event_filter.rs) - needless_borrow (event_filter.rs) - manual_is_multiple_of (event_listener.rs) - clone_on_copy (serializable_event.rs) Remaining (require manual judgment, deferred): large_enum_variant (server.rs), should_implement_trait for from_str (event_listener.rs). --- backend/src/lib/event_filter.rs | 4 ++-- backend/src/lib/event_listener.rs | 2 +- backend/src/lib/serializable_event.rs | 2 +- backend/src/lib/server.rs | 8 ++------ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/backend/src/lib/event_filter.rs b/backend/src/lib/event_filter.rs index 41f8373..81f5311 100644 --- a/backend/src/lib/event_filter.rs +++ b/backend/src/lib/event_filter.rs @@ -63,7 +63,7 @@ pub struct ArrayPrefixFilter { impl ArrayPrefixFilter { /// Checks if input array starts with filter values (prefix match) - pub fn matches(&self, value: &Vec) -> bool { + pub fn matches(&self, value: &[T]) -> bool { self.values.is_empty() || value.starts_with(&self.values) } @@ -192,7 +192,7 @@ impl EventFilter { return true; } - if self.includes_native_transfers() && is_native_transfer(&event) { + if self.includes_native_transfers() && is_native_transfer(event) { return true; } diff --git a/backend/src/lib/event_listener.rs b/backend/src/lib/event_listener.rs index 27a8522..d40001c 100644 --- a/backend/src/lib/event_listener.rs +++ b/backend/src/lib/event_listener.rs @@ -284,7 +284,7 @@ pub fn run_event_listener( last_event_timestamp_ns = Some(event.info().record_epoch_nanos); event_count += 1; - if event_count % 100 == 0 { + if event_count.is_multiple_of(100) { debug!("Processed {} events", event_count); } diff --git a/backend/src/lib/serializable_event.rs b/backend/src/lib/serializable_event.rs index 2005903..f5faba6 100644 --- a/backend/src/lib/serializable_event.rs +++ b/backend/src/lib/serializable_event.rs @@ -326,7 +326,7 @@ impl From<&EventData> for SerializableEventData { txn_hash: data.txn_hash.map(B256::from), payload: SerializableExecEvent::from(&data.payload), seqno: data.seqno, - timestamp_ns: data.timestamp_ns.clone(), + timestamp_ns: data.timestamp_ns, } } } diff --git a/backend/src/lib/server.rs b/backend/src/lib/server.rs index a2c470c..0c795e2 100644 --- a/backend/src/lib/server.rs +++ b/backend/src/lib/server.rs @@ -80,7 +80,7 @@ impl TPSTracker { self.block_2_txs = self.block_3_txs; self.block_3_txs = self.current_tx_count; self.current_tx_count = 0; - return self.block_1_txs + self.block_2_txs + (self.block_3_txs / 2); + self.block_1_txs + self.block_2_txs + (self.block_3_txs / 2) } } @@ -289,11 +289,7 @@ async fn run_event_forwarder_task( } // Send accesses update on BlockEnd events (after all access events are processed) - let send_accesses_update = if let EventName::BlockEnd = event_data.event_name { - true - } else { - false - }; + let send_accesses_update = matches!(event_data.event_name, EventName::BlockEnd); let _ = event_broadcast_sender.send(EventDataOrMetrics::Event(event_data)); From 5dc6983e34d6ef5c8dd9974f2b5118e8191daad2 Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:25:04 +0000 Subject: [PATCH 5/6] fix(backend): resolve non-auto-fixable clippy lints - large_enum_variant: box the 640-byte Event variant of EventDataOrMetrics (Event(Box)). Since From::from infers its parameter type from the argument (deref coercion does not apply), the match-site call passes &*event_data to select From<&EventData>; construction uses Box::new(..). - should_implement_trait: rename inherent EventName::from_str -> from_name (and its single caller) so it no longer shadows std::str::FromStr::from_str. --- backend/src/lib/event_listener.rs | 4 ++-- backend/src/lib/server.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/lib/event_listener.rs b/backend/src/lib/event_listener.rs index d40001c..6d311fc 100644 --- a/backend/src/lib/event_listener.rs +++ b/backend/src/lib/event_listener.rs @@ -85,7 +85,7 @@ impl EventName { } } - pub fn from_str(s: &str) -> Option { + pub fn from_name(s: &str) -> Option { match s { "RECORD_ERROR" => Some(EventName::RecordError), "BLOCK_START" => Some(EventName::BlockStart), @@ -157,7 +157,7 @@ fn event_to_data(event: &EventDescriptor) -> Option } = event.info(); // Convert event_type to EventName enum for type safety - let event_name = EventName::from_str(EXEC_EVENT_NAMES[event_type as usize])?; + let event_name = EventName::from_name(EXEC_EVENT_NAMES[event_type as usize])?; // Get block number if present let block_number = if flow_info.block_seqno != 0 { diff --git a/backend/src/lib/server.rs b/backend/src/lib/server.rs index 0c795e2..57766bd 100644 --- a/backend/src/lib/server.rs +++ b/backend/src/lib/server.rs @@ -43,7 +43,7 @@ pub struct TopAccessesData { #[derive(Debug, Clone)] pub enum EventDataOrMetrics { - Event(EventData), + Event(Box), TopAccesses(TopAccessesData), TPS(usize) } @@ -95,7 +95,7 @@ fn process_event( ) { match event { EventDataOrMetrics::Event(event_data) => { - let serializable = SerializableEventData::from(&event_data); + let serializable = SerializableEventData::from(&*event_data); if filter.matches_event(&serializable) { events_buf.push(serializable); } @@ -291,7 +291,7 @@ async fn run_event_forwarder_task( // Send accesses update on BlockEnd events (after all access events are processed) let send_accesses_update = matches!(event_data.event_name, EventName::BlockEnd); - let _ = event_broadcast_sender.send(EventDataOrMetrics::Event(event_data)); + let _ = event_broadcast_sender.send(EventDataOrMetrics::Event(Box::new(event_data))); if send_accesses_update { let top_accesses_data = TopAccessesData { From 336dfaf3c540b7fba9f9a7d631da2b15ca97889e Mon Sep 17 00:00:00 2001 From: kyscott18 <43524469+kyscott18@users.noreply.github.com> Date: Tue, 9 Jun 2026 19:31:00 +0000 Subject: [PATCH 6/6] fix(backend): remove redundant u64 casts in client (unnecessary_cast) Surfaced once the lib compiled clean: timestamp_ns is u64, so the (u64 - u64) as u64 casts are redundant; drop the cast and parens. --- backend/src/bin/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/bin/client.rs b/backend/src/bin/client.rs index 4dbb548..85309ef 100644 --- a/backend/src/bin/client.rs +++ b/backend/src/bin/client.rs @@ -110,7 +110,7 @@ async fn main() -> Result<(), Box> { }, SerializableExecEvent::TxnEvmOutput { txn_index, .. } => { if let Some((txn_hash, txn_start_ns)) = client_state.txs_start_ns.remove(&txn_index) { - let txn_duration = std::time::Duration::from_nanos((event.timestamp_ns - txn_start_ns) as u64); + let txn_duration = std::time::Duration::from_nanos(event.timestamp_ns - txn_start_ns); client_state.block_txns_total_duration += txn_duration; log_event!("TxnEvmOutput", txn_index = txn_index, txn_hash = txn_hash, duration = txn_duration); @@ -120,7 +120,7 @@ async fn main() -> Result<(), Box> { }, SerializableExecEvent::BlockPerfEvmExit => { log_event!("BlockPerfEvmExit"); - let block_duration = std::time::Duration::from_nanos((event.timestamp_ns - client_state.block_start_ns) as u64); + let block_duration = std::time::Duration::from_nanos(event.timestamp_ns - client_state.block_start_ns); let parallel_execution_savings = client_state.block_txns_total_duration.checked_sub(block_duration); let savings_pct = if parallel_execution_savings.is_none() { // This only happens with really small/empty blocks error!("Parallel execution savings is negative: txs={:?} block={:?} height={}", client_state.block_txns_total_duration, block_duration, client_state.current_block_number);