Railguard

Terminal UI

Guide to the Railguard Terminal User Interface for monitoring transactions.

Railguard includes a Terminal User Interface (TUI) built with ratatui that displays real-time transaction monitoring.

Layout

┌─ Railguard ────────────────────────────────────────────────────────────────────┐
│ Status: Running on http://127.0.0.1:8545                                       │
├─────────────────────────────────────────┬──────────────────────────────────────┤
│ Transactions                            │ Details                              │
│                                         │                                      │
│ [PASS] eth_sendTx -> 0xa0b8... (0x1a2b) │ ID: 550e8400-e29b-41d4...           │
│ [PASS] eth_sendTx -> 0xa0b8... (0x3c4d) │ Time: 2024-01-20T10:15:32Z          │
│ [BLOCK] eth_sendTx -> 0xdead...         │ Method: eth_sendTransaction          │
│         Contract not in allowlist       │ From: 0xf39Fd6e51...                │
│ [PASS] eth_sendRawTx -> 0x7a25... (0x5e)│ To: 0xA0b86991...                   │
│                                         │ Value: 0                             │
│                                         │ Selector: 0xa9059cbb                 │
│                                         │ Verdict: Allowed                     │
│                                         │ Latency: 124µs                       │
├─────────────────────────────────────────┴──────────────────────────────────────┤
│ Logs                                                                           │
│ [INFO] Proxy started on 127.0.0.1:8545                                        │
│ [DEBUG] Forwarded eth_blockNumber to upstream                                  │
└────────────────────────────────────────────────────────────────────────────────┘

Panels

Status Bar

Shows the current proxy status and listen address:

  • Running — Proxy is active and accepting requests
  • Starting — Proxy is initializing
  • Shutting down — Graceful shutdown in progress

Transactions List

A scrolling list of all transaction attempts:

IndicatorMeaning
[PASS]Transaction allowed and forwarded (green)
[BLOCK]Transaction blocked by policy (red)

Each entry shows:

  • JSON-RPC method (eth_sendTransaction or eth_sendRawTransaction)
  • Destination address (truncated)
  • Transaction hash if forwarded (truncated)
  • Block reason if blocked

Details Panel

When a transaction is selected, shows full details:

FieldDescription
IDUnique receipt UUID
TimeTimestamp of the attempt
MethodJSON-RPC method name
FromSender address
ToDestination address
ValueETH value in wei
Selector4-byte function selector (if calldata present)
VerdictAllowed or Blocked { reason }
LatencyPolicy inspection time in microseconds
Tx HashTransaction hash (if forwarded successfully)

Logs Panel

System logs showing:

  • Proxy lifecycle events
  • Read-only request forwarding
  • Upstream connection status
  • Errors and warnings

Keyboard Controls

KeyAction
/ kMove selection up
/ jMove selection down
Page UpScroll up one page
Page DownScroll down one page
HomeJump to first entry
EndJump to last entry
q / Ctrl+CQuit
lToggle logs panel
?Show help

Color Coding

The TUI uses colors to quickly identify transaction status:

ColorMeaning
GreenTransaction allowed and forwarded
RedTransaction blocked by policy
YellowWarning (e.g., decode error in monitor mode)
BlueInformational
GrayRead-only requests (not shown in main list)

Non-Interactive Mode

When running in a non-TTY environment (CI/CD, piped output), Railguard automatically disables the TUI and outputs structured logs instead:

# Force non-interactive output
rg run -- forge script Deploy.s.sol 2>&1 | tee output.log

Output format:

[2024-01-20T10:15:32Z INFO] Railguard proxy listening on 127.0.0.1:8545
[2024-01-20T10:15:33Z INFO] [PASS] eth_sendTransaction -> 0xa0b8...eb48 (0x1a2b3c4d...)
[2024-01-20T10:15:34Z WARN] [BLOCK] eth_sendTransaction -> 0xdead...beef: Contract not in allowlist

Receipt Structure

Each transaction generates a Receipt that powers the TUI display:

pub struct Receipt {
    pub id: Uuid,                    // Unique identifier
    pub timestamp: DateTime<Utc>,    // When it occurred
    pub method: String,              // JSON-RPC method
    pub from: Option<Address>,       // Sender
    pub to: Option<Address>,         // Destination
    pub value: Option<U256>,         // ETH value
    pub selector: Option<[u8; 4]>,   // Function selector
    pub verdict: Verdict,            // Allowed or Blocked
    pub tx_hash: Option<B256>,       // Hash if forwarded
    pub latency_us: u64,             // Inspection time
}

Event Channel

The TUI receives events from the proxy via an async channel:

// Proxy sends events
let _ = state.event_sender.send(ProxyEvent { receipt }).await;
 
// TUI receives and renders
while let Some(event) = event_rx.recv().await {
    tui_state.receipts.push(event.receipt);
    terminal.draw(|f| draw(f, &tui_state))?;
}

This architecture keeps the proxy responsive—TUI rendering never blocks request handling.

Customization

Currently, the TUI layout is fixed. Future versions may support:

  • Configurable panel sizes
  • Theme customization
  • Export to JSON/CSV
  • Filtering by verdict or address

Troubleshooting

TUI Not Rendering

If the TUI doesn't appear:

  1. Check terminal size — Minimum 80x24 recommended
  2. Check TTY — Must be running in a terminal, not piped
  3. Check TERM variable — Should be set (e.g., xterm-256color)

Flickering

If the display flickers:

  1. Use a terminal with better rendering (iTerm2, Alacritty, kitty)
  2. Increase terminal buffer size
  3. Check for high CPU usage

Missing Characters

If icons don't render:

  1. Install a Nerd Font (Fira Code Nerd Font recommended)
  2. Configure your terminal to use the font
  3. Check Unicode support

Next Steps

On this page