Commit 6160c74
implement monitorv2 - comprehensive blockchain performance monitoring tool (#620)
* fix: mint to sender
The default behavior of minting to the sender causes issues when using
this contract with the deterministic deployer since it can't receive
the NFT. I'm removing this feature since I don't think it's needed.
* feat: add monitorv2 architecture with JSON renderer
Establish foundational architecture for monitorv2, a decomposed and
maintainable blockchain monitoring tool inspired by atop.
- feat(blockstore): add interface and PassthroughStore for RPC data access
- feat(indexer): add core indexing with configurable polling and concurrency
- feat(renderer): add pluggable interface with JSON implementation
- feat(monitorv2): add CLI command with --rpc-url flag
The JSON renderer demonstrates end-to-end functionality by fetching latest
blocks from any Ethereum RPC endpoint and outputting them as line-delimited
JSON events. This establishes the data flow pattern for future TUI and other
renderer implementations.
Architecture follows design principles from cmd/monitorv2/architecture.md
with clean separation of concerns between RPC access, data indexing, and
output rendering.
* feat(monitorv2): implement channel-based block monitoring with lookback
- Add monitorv2 command with pluggable architecture for blockchain monitoring
- Create blockstore interface with PassthroughStore implementation for direct RPC access
- Implement channel-based indexer that publishes blocks to consumer renderers
- Add JSONRenderer that outputs line-delimited JSON for streaming consumption
- Support initial lookback feature to fetch recent blocks on startup for context
- Use zerolog logging pattern consistent with project standards
The architecture ensures no missed blocks through producer-consumer channels
and provides clean separation between RPC access, indexing, and rendering.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(indexer): add parallel block fetching for improved gap handling
- Implement fetchBlocksInParallel() function with concurrency control via workerSem
- Replace sequential block fetching in initialCatchup() with parallel implementation
- Replace sequential gap filling in checkForNewBlocks() with parallel fetching
- Maintain block ordering by collecting results in indexed slice before publishing
- Add comprehensive logging for parallel fetch operations and success/failure tracking
- Utilize existing maxConcurrency configuration to respect RPC endpoint limits
Dramatically improves performance when catching up on missed blocks or during
initial startup with large lookbackDepth values. Individual block fetch failures
are handled gracefully without stopping the entire catchup process.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): add TUI renderer with page-based navigation architecture
- Add TviewRenderer as alternative to JSON renderer using github.com/rivo/tview
- Implement page-based architecture with home, block detail, info, and help pages
- Create compact borderless table view showing block number, hash, and transaction count
- Add comprehensive keyboard shortcuts (q=quit, h=help, i=info, Esc=back, Enter=details)
- Support both --renderer tview and --renderer tui flags for terminal UI mode
- Implement real-time block updates via channel consumption from indexer
- Add quit confirmation modal to prevent accidental exits
- Structure renderer for easy extensibility with placeholder pages for future features
The TUI provides a live-updating, interactive view of blockchain data with
intuitive navigation and a clean, compact interface similar to htop/atop.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(chainstore): replace BlockStore with unified ChainStore architecture
- Rename blockstore package to chainstore for comprehensive chain data management
- Create unified ChainStore interface consolidating block and chain metadata access
- Implement intelligent caching system with TTL-based strategies for different data types:
* Static data (ChainID): Never expires
* Semi-static (Safe/Finalized blocks): 5 minutes
* Frequent (Gas price, Fee history): 30 seconds
* Very frequent (Pending/Queued txs): 5 seconds
* Block-aligned (Base fee): Per block expiration
- Add comprehensive RPC capability detection with automatic method testing
- Enhance PassthroughStore with chain info methods and integrated caching
- Update indexer to use ChainStore interface with delegation methods
- Extend TUI renderer with real-time chain information display:
* Chain ID, gas price (in gwei), pending transaction count
* Safe/finalized block numbers, base fee
* Periodic updates every 10 seconds with graceful error handling
- Add utility functions for hex parsing and Wei/Gwei conversion
- Maintain backward compatibility while extending functionality
The unified architecture provides a single source of truth for all chain data
with appropriate caching strategies, capability-aware RPC calls, and rich
real-time information display in the terminal interface.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): enhance TUI with comprehensive blocks table and status info
- Expand blocks table from 3 to 9 columns with detailed blockchain data:
* Add TIME column with human-readable relative timestamps (5m ago, 2h ago)
* Add SIZE column with formatted byte sizes (1.5KB, 2.3MB)
* Add GAS USED column with comma-separated numbers for readability
* Add GAS % column showing utilization percentage of gas limit
* Add GAS LIMIT column with formatted numbers
* Add STATE ROOT column with truncated hash display
- Implement 6 new formatting utility functions for data presentation:
* formatRelativeTime() for time-since display
* formatBytes() for human-readable sizes
* formatNumber() for comma-separated large numbers
* formatGasPercentage() for gas utilization calculations
* truncateHash() for abbreviated hash display with ellipsis
- Enhance status pane with comprehensive monitoring context:
* Add current timestamp with full date-time for screenshot documentation
* Add RPC endpoint URL for network identification and debugging
* Display connection info prominently for multi-network workflows
- Extend ChainStore interface with GetRPCURL() method for endpoint access
- Update PassthroughStore to store and expose RPC URL information
- Add indexer delegation method for RPC URL retrieval
The enhanced table provides users with a complete dashboard view of blockchain
activity with properly formatted, human-readable data. Status pane now includes
temporal and network context essential for monitoring and documentation.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(metrics): implement plugin-based metrics system with TPS, block time, and empty block tracking
- Create extensible metrics plugin architecture in indexer/metrics:
* MetricPlugin interface for pluggable metric calculations
* MetricsSystem manages plugins and coordinates real-time updates
* Thread-safe plugin registration and metric aggregation
- Implement TPS (transactions per second) metric plugin:
* 30-second rolling window for accurate TPS calculation
* Automatic pruning of old data outside time window
* Real-time calculation as new blocks arrive
- Implement empty block rate metric plugin:
* Tracks both overall and recent empty block statistics
* Rolling window of last 100 blocks for recent rate analysis
* Provides comprehensive stats: total, rate percentages, window size
- Implement average block time metric plugin:
* Calculates time duration between consecutive blocks
* Handles out-of-order block arrival with proper chronological sorting
* Provides average, min, max block times with statistical analysis
* Excludes first block (no previous) from calculations
- Enhance TUI with 3-column top pane layout:
* Left: Status information (time, RPC, chain data)
* Center: Real-time metrics display (TPS, block time, empty blocks)
* Right: Network information placeholder for future features
- Add metrics consumption and display in TviewRenderer:
* Real-time metrics updates via dedicated goroutine
* Human-readable formatting for durations (ms, s, m)
* Comprehensive metrics display with update timestamps
- Integrate metrics system with indexer:
* Process all blocks through metrics plugins before publishing
* Provide metrics channel access for renderers
* Proper shutdown handling for metrics system
- Update architecture documentation:
* Document plugin-based metrics approach and benefits
* Explain extensibility for future metric implementations
* Update current implementation status and feature completions
The plugin architecture enables easy addition of new metrics (gas utilization,
MEV analysis, network participation) without modifying existing code. Each metric
operates independently with its own calculation window and update frequency.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement real-time BLK row with live block data and enhanced metrics table formatting
- Add block info storage to TviewRenderer:
* Track latest, safe, and finalized block numbers with mutex protection
* Store block numbers as *big.Int for proper handling of large values
* Thread-safe access using sync.RWMutex for concurrent updates
- Implement periodic block info updates:
* fetchBlockInfo() method retrieves block numbers via indexer delegation
* updateBlockInfo() goroutine updates every 15 seconds
* Immediate fetch on startup for instant data display
* Graceful error handling with "N/A" for unsupported methods
- Transform metrics display from TextView to Table:
* Convert homeMetricsPane from *tview.TextView to *tview.Table
* Implement 8-row, 5-column structured metrics layout
* Add vertical pipe separators (|) between columns for clarity
* Cell padding with leading/trailing spaces for ` | ` visual effect
- Add real-time BLK row implementation:
* Display live latest/safe/finalized block numbers in BLK row
* formatBlockNumber() utility with thousand separators (#1,234,567)
* Thread-safe block info access in updateMetricsPane()
* Auto-refresh display when block info updates
- Enhance table width utilization:
* SetExpansion(1) on all table cells for full-width usage
* Table now fills entire metrics pane (2/3 of top section)
* Improved visual balance and space utilization
- Update layout architecture:
* Remove 3-column layout (Status/Metrics/Network)
* Implement 2-column layout: Status (1/3) + Metrics Table (2/3)
* Cleaner, more focused interface prioritizing metrics display
The BLK row now shows real blockchain state with formatted block numbers
that automatically update every 15 seconds. The enhanced table formatting
provides clear visual separation and optimal space usage.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement real-time THR row with block-count based throughput metrics
- Create comprehensive ThroughputMetric plugin:
* Block-count based windows (10 and 30 blocks) instead of time-based
* Calculates TPS10, TPS30, GPS10, GPS30 in single efficient plugin
* Rolling window of last 30 blocks for both short and medium-term metrics
* Thread-safe with mutex protection for concurrent block processing
- Add throughput calculation algorithms:
* TPS (Transactions Per Second): sum(transactions) / (newest_time - oldest_time)
* GPS (Gas Per Second): sum(gas_used) / (newest_time - oldest_time)
* Robust error handling for edge cases (insufficient blocks, zero timespan)
* Maintains newest-first block ordering for efficient window calculations
- Register ThroughputMetric plugin in metrics system:
* Integrates seamlessly with existing plugin architecture
* Processes blocks automatically via indexer block processing pipeline
* Real-time updates through established metrics channel system
- Implement THR row display with real metrics data:
* Replace placeholders with live calculated throughput values
* Add metric prefixes (tps10, tps30, gps10, gps30) for clear identification
* Graceful fallback to "N/A" when insufficient blocks available
- Add formatThroughput utility function:
* Smart scaling with G/M/K suffixes for readability
* Clean formatting without redundant unit labels
* Handles zero values and empty units appropriately
- THR row now displays: "THR | tps10 15.2 | tps30 18.7 | gps10 2.1M | gps30 2.3M |"
The implementation provides real-time blockchain throughput visibility with both
transaction rate and gas consumption metrics across 10-block and 30-block windows.
Block-count based calculation ensures accurate measurement regardless of variable
block times, giving users precise network performance insights.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): add block interval column and enhanced time formatting
- Add new "INTERVAL" column showing time between blocks in seconds
- Enhanced time display format: "2026-06-09T07:47:54Z - 6m ago"
- Track blocks by hash for efficient parent block lookup
- Implement memory management to limit stored blocks to 1000
- Auto-select most recent block on startup with 2s delay
This improves block monitoring by showing:
1. Absolute timestamps for precise time tracking
2. Relative time for quick understanding ("6m ago")
3. Block intervals to identify timing patterns or issues
4. Most recent blocks immediately visible on startup
* feat(monitorv2): add real-time txpool status to POOL metrics row
Implement comprehensive txpool status display in the POOL row by:
- Add GetTxPoolStatus method to ChainStore interface and implementations
- Display real pending and queued transaction counts from txpool_status RPC
- Parse hex values to decimal with proper error handling
- Show "N/A" when txpool_status is not supported
- Add hexToDecimal utility function for flexible number parsing
The POOL row now shows real-time transaction pool data instead of
placeholder values, providing insight into network congestion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* refactor(monitorv2): replace fragile timing heuristics with clean data/view architecture
Completely refactor block handling to eliminate timing-based guesswork and
create a robust foundation for future features like column sorting and follow mode.
**New Architecture:**
- ViewState struct to track follow mode, selection state, and sort preferences
- Binary search insertion to maintain blocks in sorted order always
- Clean separation of data management from view state logic
- Thread-safe access with separate mutexes for blocks and view state
**Improvements:**
- ✅ Eliminates all timing heuristics and sleep-based catchup detection
- ✅ Consistent block ordering regardless of RPC response speed
- ✅ Predictable selection behavior (auto-follow newest vs manual selection)
- ✅ Foundation for future features (column sorting, follow mode toggle)
- ✅ Thread-safe data access with proper synchronization
- ✅ Deadlock-free mutex usage with separate locks for data vs view state
**Key Changes:**
- Replace chaotic append/prepend/sort logic with insertBlockSorted()
- Add applyViewState() for clean view state management
- Remove finishInitialCatchup() and all timing guesswork
- Add manual selection detection to disable auto-follow
- Use binary search for O(log n) insertion in sorted order
- Fix deadlock issues with proper mutex separation
This provides a robust, maintainable foundation that works correctly
with both fast and slow RPC endpoints without blocking issues.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement responsive column sorting with immediate feedback
Adds comprehensive column sorting functionality to the monitorv2 TUI with instant user feedback:
Core sorting features:
- Column navigation: '<' and '>' keys to move between sort columns
- Sort direction toggle: 'R' key to reverse ascending/descending order
- Visual indicators: Headers show ↑/↓ arrows for current sort column
- Immediate response: Sorting happens instantly on key press, no waiting for next block
- Generic sorting system supporting all 10 columns with custom comparators
Sortable columns:
- Block number, timestamp, interval, hash, transaction count
- Block size, gas used/limit, gas percentage, state root
- Smart comparison functions for numbers, strings, and computed values
Architecture improvements:
- Thread-safe design with separate mutexes for blocks vs view state
- Binary search insertion maintains sort order for new blocks
- Keyboard handlers trigger immediate sort + redraw on main UI thread
- ColumnDef struct with custom sort/compare functions for each column type
Performance and stability fixes:
- Increased metrics channel buffer from 100 to 10,000 to prevent goroutine blocking
- Added --pprof flag for debugging deadlocks and performance issues
- Replaced QueueUpdateDraw with direct Draw() calls and throttling
- Eliminated UI freezing by removing cross-thread update dependencies
User experience: Pressing '<', '>', or 'R' now provides instant visual feedback,
making the sorting feel responsive and intuitive like a modern terminal application.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): optimize network RPC calls with periodic caching
This change implements network info caching to reduce excessive RPC calls
from 15 per block to 1 per 5 seconds, dramatically improving performance.
Changes:
- Add GetNetPeerCount to ChainStore interface and PassthroughStore implementation
- Add GetNetPeerCount delegation method to Indexer
- Implement periodic network info caching in TviewRenderer
- Cache gas price, txpool status (pending/queued), and peer count
- Update cached values every 5 seconds instead of per metric update
- Use cached values in updateMetricsPane instead of making RPC calls
- Update PEER row to show actual peer count from net_peerCount
Performance improvement: Reduces network RPC calls from ~15 per block to
~3 per 5 seconds (5x reduction in frequency), preventing UI lag and
reducing load on RPC endpoints.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement independent scrollable panes in block detail view
- Convert block detail left pane from TextView to Table for transaction display
- Add transaction table with columns: index, from, to, gas limit, input data
- Make both panes (transaction table and JSON view) independently focusable
- Implement Tab navigation to switch focus between panes
- Add keyboard shortcuts for block-detail page (Tab, Enter)
- Set initial focus to transaction table when entering block detail
- Handle contract creation transactions (show "CONTRACT" for empty To address)
- Maintain raw JSON view in right pane with pretty formatting
- Fix border consistency between panes (resolves double border visual issue)
Users can now:
- Navigate between transaction table and JSON pane using Tab
- Scroll independently in each pane
- Select transactions with arrow keys and Enter
- View comprehensive block data in both structured and raw formats
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): add transaction receipt display and fix empty receipt JSON
Add comprehensive transaction detail view functionality to monitorv2:
- Implement transaction receipt fetching and display in left pane of transaction detail view
- Add MarshalJSON() method to PolyReceipt interface and implPolyReceipt implementation
- Fix empty `{}` JSON display by enabling proper receipt marshaling
- Add navigation from block detail to transaction detail with Enter key
- Include dynamic pane titles showing transaction index and hash
- Add proper error handling for pending/unavailable receipts
- Implement Tab key navigation between receipt and transaction JSON panes
Technical changes:
- Add MarshalJSON() to PolyReceipt interface in rpctypes/rpctypes.go
- Implement MarshalJSON() for implPolyReceipt struct to marshal inner RawTxReceipt
- Enhance showTransactionDetail() function to fetch and display receipt JSON
- Add transaction selection handling in block detail view
- Update transaction detail page layout to side-by-side panes
Users can now navigate through blocks → transactions → view both receipt and
transaction data in formatted JSON, providing comprehensive transaction analysis.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement async transaction detail loading with 4byte.directory signature lookup
- Restructure transaction detail page with 3-pane layout: human-readable details on left, stacked JSON views on right
- Add signature lookup integration with 4byte.directory API for method signature resolution
- Implement async loading pattern: show page immediately with loading states, update progressively as data arrives
- Add comprehensive caching layer for signatures with configurable TTL (1 hour default)
- Enhance user experience with progressive enhancement: basic details first, then enriched with signatures
- Add proper error handling and graceful degradation for failed API calls
- Use thread-safe UI updates via app.QueueUpdateDraw() for all async operations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(monitorv2): coordinate async loading to prevent race condition between method signatures and event logs
- Replace independent async updates with coordinated loading mechanism
- Wait for both method signature lookup and event log parsing to complete before updating UI
- Use channels to synchronize async responses and combine results atomically
- Eliminate race condition where method signatures could overwrite event logs or vice versa
- Maintain progressive loading: basic details first, then enhanced details with both signatures and logs
- Consolidate event log processing into the coordinated loading flow
- Ensure users always see complete transaction details without overwrites
This fixes the issue where async responses could overwrite each other, ensuring users see both method signatures and event logs together in the final transaction details view.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement breadcrumb-style navigation with escape key
Modify escape key behavior to provide intuitive back navigation instead of
always returning to home page. From transaction detail page, escape now
returns to block detail page, creating a breadcrumb navigation flow:
Home → Block Detail → Transaction Detail → (escape) → Block Detail → (escape) → Home
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement EOA and contract deployment counters in SIG1 metrics
Add real-time transaction analysis to the SIG1 metrics row by implementing:
- EOA counter: tracks transactions with no input data sent to non-zero addresses
- Contract deployment counter: tracks transactions with input data sent to zero address
- calculateTransactionCounters() method that analyzes all blocks in the store
- Thread-safe counter fields with mutex protection
Replaces placeholder values in SIG1 row with actual counts formatted with
thousand separators (e.g. "EOA 1,234" and "deploy 56").
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement ERC20 and NFT transaction counters in SIG2 metrics
Add method selector-based transaction analysis to the SIG2 metrics row:
- ERC20 counter: tracks transactions with transfer() method selector (0xa9059cbb)
- NFT counter: tracks transactions with safeTransferFrom() and setApprovalForAll() selectors
- calculateERC20NFTCounters() method that analyzes transaction input data
- Thread-safe counter fields extending existing metrics infrastructure
Method selectors tracked:
- ERC20: 0xa9059cbb (transfer)
- NFT: 0xb88d4fde, 0x42842e0e (safeTransferFrom variants), 0xa22cb465 (setApprovalForAll)
Replaces placeholder values in SIG2 row with actual counts formatted with
thousand separators (e.g. "ERC20 1,234" and "NFT 567").
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* perf(monitorv2): optimize transaction counters with string-based method selector matching
Replace expensive hex decoding operations with direct string prefix matching to
significantly reduce CPU usage in transaction counter calculations.
Changes:
- Add DataStr() method to PolyTransaction interface for direct hex string access
- Update calculateTransactionCounters() to use string length check instead of byte conversion
- Replace byte-based method selector extraction with string prefix matching in calculateERC20NFTCounters()
- Eliminate hex.DecodeString() calls that were happening for every transaction on every metrics update
Performance improvements:
- No hex decoding overhead (removes normalizeHexString → hex.DecodeString chain)
- No memory allocation for byte arrays
- Simple string operations (len() and strings.HasPrefix()) are much faster
- Better cache efficiency with string operations
The optimization maintains identical functionality while dramatically reducing CPU usage
during metrics updates, especially noticeable with large numbers of blocks/transactions.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): implement unique from/to address counters in ACCO metrics
- Add calculateUniqueAddressCounters() method to track unique addresses
- Count distinct from addresses across all transactions
- Count distinct to addresses (excluding zero address for contract creation)
- Display counts in ACCO row with thousand separators using formatNumber()
- Follow existing counter pattern used in SIG1 and SIG2 rows for consistency
- Provide real-time unique address tracking based on loaded block data
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(monitorv2): implement modal focus management to prevent quit dialog focus loss
- Add modal state tracking (isModalActive, activeModalName) with thread-safe access
- Create modal management methods: showModal(), hideModal(), isModalCurrentlyActive()
- Update quit dialog to use new modal system with explicit focus setting
- Protect modal focus during background UI updates in throttledDraw()
- Automatically restore modal focus after redraw operations
- Future-proof design for additional modals like search functionality
Resolves issue where quit dialog ('q' key) loses focus during UI refreshes,
making it impossible to quit when background updates occur every few seconds.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* docs: updating monitorv2 architecture
* feat(monitorv2): implement comprehensive search functionality with proper modal UX
- Replace broken Flex-based search modal with proper Form implementation
- Add support for searching blocks by number and blocks/transactions by hash
- Implement smart input detection (numeric vs hash format)
- Add async search operations with proper error handling
- Enable seamless navigation: transaction searches load containing block for proper back navigation
- Fix search modal UX issues: proper background masking, text input capture, and keyboard handling
- Add ethereum/go-ethereum/common import for hash handling
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* perf(monitorv2): optimize address counting functions to eliminate expensive Hex() calls
- Add zeroAddress constant for efficient address comparisons
- Replace map[string]bool with map[common.Address]bool in calculateUniqueAddressCounters
- Eliminate tx.From().Hex() and tx.To().Hex() calls in counting loops
- Use direct common.Address comparison instead of hex string comparison
- Remove thousands of Keccak256 hash computations from checksumHex() per UI update
Resolves performance bottleneck where calculateTransactionCounters and
calculateUniqueAddressCounters were performing expensive cryptographic
operations on every address conversion, causing significant CPU load
during UI updates with many transactions.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): enable auto-follow re-activation by selecting first row
Previously, once a user manually selected a block (disabling auto-follow), there was no way to re-enable auto-follow mode. This made it difficult to return to tracking the latest blocks after exploring historical data.
Now, selecting the first data row (row 1) will re-enable auto-follow mode, allowing the focus to stay at the top as new blocks arrive. This provides an intuitive way for users to toggle between manual navigation and auto-follow modes.
- Modified selection change handler to detect first row selection
- Clear manual selection flag when row 1 is selected
- Maintain existing behavior for other rows (disable auto-follow)
- Added debug logging for auto-follow state changes
* feat(monitorv2): enhance status pane with network info and optimize RPC performance
This commit transforms the status pane into a comprehensive network information display while dramatically improving initial loading performance.
Enhanced Status Information:
- Network name resolution using chainlist.org API with static fallback mapping
- Client version display (e.g., "Geth/v1.10.25-stable", "Bor/v0.4.0")
- Real-time sync status with ASCII indicators: [OK] Synced, [SYNC] Syncing (85.2%), [?] Unknown
- Simplified, clean status layout showing essential connection context
Network Name Resolution:
- Downloads and caches chain information from chainlist.org
- Static fallback mapping for 30+ major networks (Ethereum, Polygon, Arbitrum, Base, etc.)
- Graceful degradation to "Chain X" format for unknown networks
- Background HTTP client with 10-second timeout
Performance Optimizations:
- Use optimistic RPC calls for core methods (eth_chainId, web3_clientVersion, eth_syncing)
- Remove capability checking dependency for universally supported methods
- Implement concurrent capability detection using goroutines and channels
- Reduce total capability detection time from ~80 seconds to ~5 seconds
- Status pane now loads immediately instead of waiting for background processes
Infrastructure Changes:
- Extended ChainStore interface with GetClientVersion and GetSyncStatus methods
- Enhanced caching system with different TTL strategies for different data types
- Added capability detection for web3_clientVersion and eth_syncing methods
- Improved error handling and logging throughout the RPC layer
Focus Behavior Fix:
- Enable auto-follow re-activation by selecting the first row
- Clear manual selection flag when user returns to top of block list
- Provide intuitive toggle between manual navigation and auto-follow modes
The status pane now provides immediate, comprehensive connection context:
Time, RPC URL, Network Name, Chain ID, Client Version, and Sync Status
* feat(monitorv2): add real-time connection latency measurement to status pane
Adds TCP connection latency measurement to provide immediate visibility into RPC endpoint connectivity quality alongside existing network information.
Connection Latency Features:
- Measures pure TCP connection time separate from RPC request processing
- Real-time quality assessment with descriptive ASCII indicators
- Periodic measurement integrated into 5-second network info update cycle
- Proper error handling for connection failures
Quality Indicators:
- [OK] Excellent (< 50ms), Good (50-150ms), Fair (150-300ms)
- [SLOW] Slow (300-500ms), Poor (500ms-1s)
- [POOR] Very Poor (> 1s)
- [ERROR] Connection failed
Implementation:
- Added MeasureConnectionLatency() method to ChainStore interface
- TCP connection measurement in PassthroughStore with URL parsing
- Automatic port detection for HTTP/HTTPS/WS/WSS schemes
- Cached connection status display in renderer
- Enhanced status pane with connection quality information
The status pane now shows comprehensive connection context:
Time, RPC URL, Network Name, Chain ID, Client Version, Sync Status, and Connection Quality
This provides users with immediate insight into network performance issues separate from server processing delays.
* fix(monitorv2): prevent auto-follow from stealing focus from quit dialog
When new blocks arrived while the quit dialog was open, the auto-follow
functionality would steal focus away from the modal, making it unresponsive
to keyboard input. Added modal state check to preserve focus on active modals.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(monitorv2): improve block interval calculation to handle non-consecutive blocks
Enhanced the interval calculation to work even when parent blocks are missing
from the cache. Now calculates intervals using adjacent blocks in the sorted
list when parent lookup fails. For non-consecutive blocks, displays average
interval with ~ prefix (e.g., "~2s" for averaged intervals).
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat(monitorv2): add pretty JSON formatting for blockchain data display
Add comprehensive pretty-printing functionality to make JSON output more human-readable:
- Create new rpctypes/pretty.go with formatting utilities for blockchain data
- Convert hex values to human-readable formats:
- Timestamps: "0x55ba467c" -> 1438271100 (uint64)
- Gas values: "0x5208" -> 21000 (uint64)
- Block numbers: "0x12345" -> 74565 (uint64)
- Addresses: hex strings -> common.Address type
- Hashes: hex strings -> common.Hash type
- Log data: hex strings -> []byte
- Update monitorv2 tview renderer to use pretty formatting:
- Block details now use PolyBlockToPrettyJSON
- Transaction details now use PolyTransactionToPrettyJSON
- Receipt details now use PolyReceiptToPrettyJSON
- Add comprehensive test coverage for all pretty formatting functionality
- Log entries now show readable values instead of hex strings (block numbers, indices, etc.)
Example transformation:
- Raw: "gasUsed": "0x5208", "blockNumber": "0x12345"
- Pretty: "gasUsed": 21000, "blockNumber": 74565
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* doc: make gen
* fix(monitorv2): fix search functionality with proper transaction validation
- Add transaction validation to detect empty/invalid RPC responses
- Fix issue where block hashes were incorrectly identified as transactions
- Add isValidTransaction method that checks:
- Transaction hash is not zero
- From address exists (all transactions must have a sender)
- Block number is valid (transaction has been mined)
- Improve search logic to properly fall through from transaction to block search
- Add comprehensive debug logging throughout search flow:
- Log search query parsing and type detection
- Log transaction validation results
- Log block lookup attempts with detailed validation info
- Log UI navigation calls
The search now correctly:
- Validates transaction responses before accepting them
- Falls through to block search when transaction is invalid
- Shows transaction details when searching by tx hash
- Shows block details when searching by block hash
- Handles invalid/not found hashes gracefully
* fix(monitorv2): standardize table alignment using ColumnDef configuration
Data cells now use the same alignment as defined in ColumnDef.Align instead of hardcoded values, ensuring consistency between headers and data cells. This improves visual alignment and maintainability of the table display.
* fix(monitorv2): ensure consistent navigation focus behavior
Ensures quit modal always starts on "Yes" and search modal always focuses input field.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(monitorv2): add bounds checking for unsafe uint64 to int64 conversions
Fixes 11 security vulnerabilities identified by GitHub Advanced Security where uint64 values were being converted to int64 without bounds checking, potentially causing integer overflow.
Changes:
- Add bounds checking for MaxFeePerGas() and MaxPriorityFeePerGas() conversions in transaction details
- Fix timestamp conversions in formatRelativeTime() and formatBlockTime() functions
- Add bounds checking for block time interval calculations
- Fix block number and numeric conversions in hexToDecimal()
- Add structured error logging when overflow conditions are detected
- Provide safe fallback values (MaxInt64, current time) to maintain functionality
The fixes prevent integer overflow vulnerabilities while preserving all existing functionality through safe fallback behavior.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(monitorv2): resolve variable shadowing issue in keyboard shortcuts
Remove redundant variable declaration that was shadowing existing currentPage variable in setupKeyboardShortcuts function, fixing go vet warning.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(lint): resolve golangci-lint errors across multiple components
Fix various linting issues identified by golangci-lint:
- Check return value of idx.Stop() in monitorv2 command
- Remove unused fields and functions in tview renderer
- Fix ineffectual assignment in transaction address handling
- Remove redundant int64 range checks for int type
- Clean up empty branch in empty block metrics
- Apply automatic formatting fixes for consistency
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix(security): add bounds checking for remaining unsafe number conversions
- Add bounds checking for uint64 to int64 conversion in RawQuantityResponse.ToInt64()
- Add missing uint64 case in hexToDecimal() function with proper bounds checking
- Ensure all large integer values are properly validated before conversion to prevent overflow
These fixes address security vulnerabilities identified in the number conversion code,
preventing potential integer overflow issues when processing blockchain data with
large numeric values.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* Potential fix for code scanning alert no. 43: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 25: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 26: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 34: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 29: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* fix(security): address remaining integer conversion vulnerabilities
- Fix variable scope issues in tview_renderer.go for maxFeeBig and maxPriorityBig
- Replace unsafe Int64() conversion with direct Cmp() in rpctypes.go SortableBlocks.Less()
- Remove impossible negative check for uint64 variable caught by staticcheck linter
These fixes address the remaining CodeQL security alerts for incorrect conversion
between integer types, ensuring all numeric conversions are safe from overflow.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* Potential fix for code scanning alert no. 44: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 38: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 42: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 46: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 39: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* Potential fix for code scanning alert no. 45: Incorrect conversion between integer types
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* fix: address integer conversion security issue in formatRelativeTime
Fixed incorrect conversion between integer types in cmd/monitorv2/renderer/tview_renderer.go:1991.
The issue was that a uint64 timestamp was being converted to int64 without proper bounds checking,
which could lead to integer overflow.
Changes:
- Added proper bounds check before converting uint64 to int64
- Return "invalid" for timestamps that exceed int64 range
- Handle future timestamps before calculating diff to avoid negative values
- Removed redundant negative diff check
This addresses CodeQL security alert for incorrect-integer-conversion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix: address integer conversion security issues in timestamp formatting
Fixed incorrect conversion between integer types in cmd/monitorv2/renderer/tview_renderer.go:1991 and :2021.
The issues were that uint64 timestamps were being converted to int64 without proper bounds checking,
which could lead to integer overflow.
Changes in formatRelativeTime (line 1991):
- Added proper bounds check before converting uint64 to int64
- Return "invalid" for timestamps that exceed int64 range
- Handle future timestamps before calculating diff to avoid negative values
- Removed redundant negative diff check
Changes in formatBlockTime (line 2021):
- Added proper bounds check before converting uint64 to int64
- Return "invalid timestamp - invalid" for timestamps that exceed int64 range
This addresses multiple CodeQL security alerts for incorrect-integer-conversion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix: address integer conversion security issues in multiple functions
Fixed incorrect conversion between integer types in:
- cmd/monitorv2/renderer/tview_renderer.go:1991 (formatRelativeTime)
- cmd/monitorv2/renderer/tview_renderer.go:2021 (formatBlockTime)
- rpctypes/rpctypes.go:688 (RawQuantityResponse.ToInt64)
The issues were that uint64 values were being converted to int64 without proper bounds checking,
which could lead to integer overflow.
Changes in formatRelativeTime:
- Added proper bounds check before converting uint64 to int64
- Return "invalid" for timestamps that exceed int64 range
- Handle future timestamps before calculating diff to avoid negative values
- Removed redundant negative diff check
Changes in formatBlockTime:
- Added proper bounds check before converting uint64 to int64
- Return "invalid timestamp - invalid" for timestamps that exceed int64 range
Changes in RawQuantityResponse.ToInt64:
- Return math.MaxInt64 directly instead of converting after assignment
- Avoid intermediate assignment that could cause overflow
This addresses multiple CodeQL security alerts for incorrect-integer-conversion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix: address integer conversion security issues in multiple functions
Fixed incorrect conversion between integer types in:
- cmd/monitorv2/renderer/tview_renderer.go (formatRelativeTime, formatBlockTime, calculateBlockInterval)
- rpctypes/rpctypes.go (RawQuantityResponse.ToInt64)
The issues were that uint64 values were being converted to int64 without proper bounds checking,
which could lead to integer overflow.
Changes in formatRelativeTime:
- Added proper bounds check before converting uint64 to int64
- Return "invalid" for timestamps that exceed int64 range
- Handle future timestamps before calculating diff to avoid negative values
- Removed redundant negative diff check
Changes in formatBlockTime:
- Added proper bounds check before converting uint64 to int64
- Return "invalid timestamp - invalid" for timestamps that exceed int64 range
Changes in calculateBlockInterval:
- Added proper bounds checks for all uint64 to int64 conversions
- Return "N/A" when time values exceed int64 range
- Removed impossible negative checks for uint64 values
- Simplified logic by checking bounds before conversion
Changes in RawQuantityResponse.ToInt64:
- Return math.MaxInt64 directly instead of converting after assignment
- Avoid intermediate assignment that could cause overflow
This addresses multiple CodeQL security alerts for incorrect-integer-conversion.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix: remove impossible uint64 comparisons in tview_renderer and rpctypes
- Remove check for blockNum < 0 in tview_renderer.go since blockNum is uint64
- Remove check for result > math.MaxUint64 in rpctypes.go since result is already uint64
- Fixes SA4003 staticcheck warnings
* fix: address integer conversion issues and impossible uint64 comparisons
Fixed multiple issues identified by golangci-lint and CodeQL:
1. Removed impossible uint64 comparisons (SA4003):
- Removed check for blockNum < 0 in tview_renderer.go since blockNum is uint64
- Removed check for result > math.MaxUint64 in rpctypes.go since result is already uint64
2. Fixed unsafe uint64 to int64 conversions in calculateBlockInterval:
- Keep timestamp calculations as uint64 to avoid overflow
- Check that blockTime >= parentTime before subtraction
- Calculate interval and average interval using uint64 arithmetic
- Removed unnecessary bounds checks for MaxInt64
* refactor: improve navigation and memory management in monitorv2
- Add maxBlocks constant (1000) to centralize block limit configuration
- Reset table selection to top when pressing ESC from home page
- Reset scroll positions when navigating to transaction detail page
- Use maxBlocks constant consistently throughout block management logic
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat: add base fee column to monitorv2 block table
Add a new "BASE FEE" column to the monitorv2 block table, positioned between
the SIZE and GAS USED columns. The base fee is displayed in human-readable
format (gwei for values ≥1 gwei, wei for smaller values) with thousand
separators for better readability.
For chains without base fee support, the column will display "0".
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat: add base fee column and improve gas formatting in monitorv2
Add a new "BASE FEE" column to the monitorv2 block table, positioned between
the SIZE and GAS USED columns. Update the GAS metrics (base10/base30) in the
top metrics section to use the same intelligent formatting.
The base fee is now displayed in human-readable format (gwei for values ≥1 gwei,
wei for smaller values) with thousand separators for better readability. This
consistent formatting is applied to both the new BASE FEE column and the existing
GAS metrics.
For chains without base fee support, the column will display "0".
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* wip: refactor
* fix: adjusting imports
* refactor: consolidate wei to gwei formatting in monitorv2 renderer
Replace weiToGwei function with existing formatBaseFee function to improve consistency and readability. The formatBaseFee function provides better formatting with thousand separators and handles edge cases like sub-gwei values more elegantly.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat: add check for chainID to detect supported network
Signed-off-by: Ji Hwan <[email protected]>
* fix: display transaction input data as hex instead of base64 in monitorv2
Addresses:
https://github.com/0xPolygon/polygon-cli/pull/620#discussion_r2179453121
Transaction input data and other byte fields in the human-readable JSON views
were being displayed as base64-encoded strings, making them difficult to read.
This change introduces a custom HexBytes type that marshals byte data as
hex strings with 0x prefix for better readability.
Updated fields:
- Transaction input data (PrettyTransaction.Input)
- Event log data (PrettyTxLogs.Data)
- Block logs bloom filter (PrettyBlock.LogsBloom)
- Block extra data (PrettyBlock.ExtraData)
- Receipt logs bloom filter (PrettyReceipt.LogsBloom)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* fix: prevent UI freeze on failed search from detail pages in monitorv2
Addresses:
https://github.com/0xPolygon/polygon-cli/pull/620#discussion_r2179462721
When searching with invalid input while viewing block or transaction details,
the UI would freeze because hideModal() always returned focus to the home table
regardless of which page was active. This created a focus/page mismatch where
the detail page was visible but focus was on an invisible element.
Fix by tracking the previous page before showing modals and restoring focus
to the appropriate UI element when hiding the modal.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
* feat: enhance wei formatting with full SI unit scale in monitorv2
Replace basic wei/gwei formatting with comprehensive SI unit scale supporting
wei, kwei, mwei, gwei, micro, milli, and ether. Automatically selects the
most appropriate unit based on magnitude for improved readability.
Improvements:
- Auto-select largest unit where result >= 1.0 (e.g., 157987 wei → 157.987 kwei)
- Add thousand separators for large wei values (1,234,567 wei)
- Clean decimal formatting (removes trailing zeros)
- Support full range from wei to ether with proper precision
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
---------
Signed-off-by: Ji Hwan <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Ji Hwan <[email protected]>1 parent 104396c commit 6160c74
File tree
45 files changed
+6810
-17
lines changed- bindings/uniswapv3
- chainstore
- cmd
- monitorv2
- renderer
- doc
- indexer
- metrics
- rpctypes
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
45 files changed
+6810
-17
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| 74 | + | |
| 75 | + | |
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments