Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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
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: pnpm-lock.yaml
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck

build:
runs-on: ubuntu-latest
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: pnpm-lock.yaml
- run: pnpm install --frozen-lockfile
- run: pnpm build

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:
- name: Install build dependencies
run: |
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
- run: cargo build --all-targets
24 changes: 0 additions & 24 deletions .github/workflows/lint.yml

This file was deleted.

1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"biome.enabled": true,
"eslint.enable": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/bin/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
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);
Expand All @@ -120,7 +120,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
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);
Expand Down
4 changes: 2 additions & 2 deletions backend/src/lib/event_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub struct ArrayPrefixFilter<T: PartialEq> {

impl<T: PartialEq> ArrayPrefixFilter<T> {
/// Checks if input array starts with filter values (prefix match)
pub fn matches(&self, value: &Vec<T>) -> bool {
pub fn matches(&self, value: &[T]) -> bool {
self.values.is_empty() || value.starts_with(&self.values)
}

Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 3 additions & 3 deletions backend/src/lib/event_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl EventName {
}
}

pub fn from_str(s: &str) -> Option<Self> {
pub fn from_name(s: &str) -> Option<Self> {
match s {
"RECORD_ERROR" => Some(EventName::RecordError),
"BLOCK_START" => Some(EventName::BlockStart),
Expand Down Expand Up @@ -157,7 +157,7 @@ fn event_to_data(event: &EventDescriptor<ExecEventDecoder>) -> Option<EventData>
} = 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 {
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion backend/src/lib/serializable_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}
14 changes: 5 additions & 9 deletions backend/src/lib/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct TopAccessesData {

#[derive(Debug, Clone)]
pub enum EventDataOrMetrics {
Event(EventData),
Event(Box<EventData>),
TopAccesses(TopAccessesData),
TPS(usize)
}
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -289,13 +289,9 @@ 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));
let _ = event_broadcast_sender.send(EventDataOrMetrics::Event(Box::new(event_data)));

if send_accesses_update {
let top_accesses_data = TopAccessesData {
Expand Down
22 changes: 22 additions & 0 deletions frontend/components/network-activity-tracker/tps-chart.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client'

import Image from 'next/image'
import { useEffect, useState } from 'react'
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
import {
type ChartConfig,
Expand All @@ -21,11 +22,28 @@ const chartConfig = {
},
} satisfies ChartConfig

/** Visible time window, matching the TPS history kept by useTps */
const WINDOW_MS = 5 * 60 * 1000

export function TpsChart() {
const { currentTps, peakTps, history } = useTps()
const totalTransactions = useTotalTransactions()
const hasData = history.length > 0

// Advance a "now" clock every animation frame so the time-windowed X axis
// domain slides continuously. New points enter smoothly from the right edge
// instead of popping in a discrete category slot.
const [now, setNow] = useState(() => Date.now())
useEffect(() => {
let frame: number
const tick = () => {
setNow(Date.now())
frame = requestAnimationFrame(tick)
}
frame = requestAnimationFrame(tick)
return () => cancelAnimationFrame(frame)
}, [])

return (
<div className="flex flex-col h-full">
<div className="flex flex-col gap-3 pb-10 xs:flex-row xs:items-start xs:justify-between">
Expand Down Expand Up @@ -77,6 +95,10 @@ export function TpsChart() {
<CartesianGrid stroke="var(--chart-grid)" vertical={false} />
<XAxis
dataKey="timestamp"
type="number"
scale="time"
domain={[Math.max(now - WINDOW_MS, history[0].timestamp), now]}
allowDataOverflow
tickLine={false}
axisLine={false}
tickMargin={8}
Expand Down
18 changes: 0 additions & 18 deletions frontend/eslint.config.mjs

This file was deleted.

4 changes: 1 addition & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@number-flow/react": "0.5.10",
Expand All @@ -31,8 +31,6 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.0.6",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5"
Expand Down
Loading