Commit 9999efc
Add web-based block explorer and transaction indexer (#98)
* Add web-based block explorer for Subcoin
Initial implementation of a React-based block explorer that connects
to a running Subcoin node via JSON-RPC.
Features:
- Dashboard with latest blocks and network status
- Block detail view with transaction list
- Transaction detail view with inputs/outputs
- Network status page with peer information
- Dark theme with Bitcoin orange accents
Tech stack:
- React 18 + TypeScript
- Vite (bundler with RPC proxy for CORS)
- Tailwind CSS
- Bun (package manager)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add real-time updates, connection status, and search to explorer
- WebSocket client subscribing to chain_subscribeNewHeads for live block updates
- Connection status indicator with auto-reconnect and exponential backoff
- Search bar supporting block height, block hash, and transaction ID lookups
- Dashboard shows "Live" indicator and last update timestamp when connected
- Fallback to 60-second polling when WebSocket is disconnected
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add UI polish: loading skeletons, mobile layout, copy buttons, confirmations
Short-term improvements:
- Loading skeleton components for Dashboard, BlockDetail, TransactionDetail, Network
- Responsive mobile layout with hamburger menu and collapsible navigation
- Copy-to-clipboard buttons for block hashes, merkle roots, and transaction IDs
- Block confirmation count badge (green for 6+, yellow for 1-5)
- Responsive table columns that hide on smaller screens
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add transaction linking, editable endpoint, and fix sync target display
- Add blockchain_getBlockWithTxids RPC methods to return blocks with
pre-computed transaction IDs for clickable tx links in explorer
- Make RPC endpoint editable in header (persisted to localStorage)
- Fix sync target display by correctly parsing network_status response
format (downloading/importing with nested target field)
- Remove broken Network page temporarily
- Add dynamic Vite proxy routing to support custom endpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add paginated Block List page
- New /blocks route with paginated block list (25 per page)
- First/Prev/Next/Last navigation buttons
- Block counter showing range and page info
- Jump to block feature for quick navigation
- Added Blocks link to navigation (desktop and mobile)
- Added "View all blocks" link on Dashboard
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Improve transaction indexer robustness with state machine
- Add IndexerState enum to track indexer state for crash recovery
- Fix bug: fresh start on existing chain now indexes all blocks
- Save progress every 1000 blocks during historical indexing
- Add progress logging with ETA during historical indexing
- Replace panic with graceful error handling in run()
- Remove unused legacy functions and constants
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Bitcoin Core compatible RPC layer for electrs integration
Introduces subcoin-rpc-bitcoind crate providing Bitcoin Core-style RPC
methods that enable Subcoin to work with electrs and other Bitcoin
ecosystem tools.
New RPC methods (enabled with --bitcoind-rpc flag):
- Blockchain: getbestblockhash, getblockchaininfo, getblockcount,
getblockhash, getblock, getblockheader
- Raw transactions: getrawtransaction, sendrawtransaction,
decoderawtransaction
- Network: getnetworkinfo
- Mempool: getrawmempool, getmempoolinfo, getmempoolentry (placeholder)
- Mining: estimatesmartfee
Both subcoin-rpc (explorer) and subcoin-rpc-bitcoind (electrs) APIs
can run simultaneously on the same RPC server.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add transaction pagination to Block details page
Implements client-side pagination for transactions in the block detail
view with 25 transactions per page. Features include:
- Page navigation with First/Prev/Next/Last buttons
- Clickable page numbers with ellipsis for large page counts
- Shows "Showing X to Y of Z transactions" status
- Preserves global transaction index (e.g., #50, #51, not #0, #1)
- Smooth scroll to transactions section on page change
- URL-based page state (?page=N) for shareable links
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add block size and weight display to Block details page
Display estimated block statistics including:
- Size (in bytes/KB/MB)
- Weight (in WU/kWU/MWU)
- Virtual size (vsize)
- SegWit transaction count and percentage
Uses client-side calculation based on transaction data according to
BIP 141 weight formula: base_size * 4 + witness_size
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Improve initial block download (IBD) sync performance
This commit addresses several bottlenecks identified during initial sync
from the Bitcoin p2p network:
1. Preserve downloaded blocks on peer switch
- Modified restart() to keep already-downloaded blocks in memory
- Only clears pending requests, not completed downloads
- Prevents wasting bandwidth when sync peer changes
2. Relax ping latency threshold during IBD
- Added PEER_LATENCY_THRESHOLD_INITIAL_SYNC (5s vs 2s normal)
- During major syncing, higher latency peers are tolerated
- Reduces unnecessary sync restarts due to high-latency disconnections
3. Add block request pipelining
- Added should_pipeline() method to trigger next batch at 50% completion
- Reduces idle time between batch downloads
- Improves single-peer throughput utilization
4. Fix stall detection during header download
- Added touch_progress() to update last_progress_time on header receipt
- Prevents false stall detection during long header downloads
- Applied to both regular and prefetch headers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add address indexing with RPC endpoints and explorer UI
Backend:
- Rewrite subcoin-indexer with SQLite-based address/UTXO indexing
- Add batch processing (100 blocks/transaction) during historical sync
- Use per-block transactions during live sync for quick availability
- Add address_* RPC endpoints: getBalance, getHistory, getUtxos, getTxCount
- Add address_indexerStatus RPC to expose sync progress
- Add blockchain_decodeScriptPubkey RPC for address decoding
- Make indexer database path network-aware (mainnet/testnet/signet/regtest)
Frontend:
- Add AddressView page with balance, transaction history, and UTXOs
- Update TransactionDetail to show decoded addresses with links
- Show indexer sync progress when transaction not found
- Add address route to explorer App
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add address statistics, search, and parallel indexing
- Add address statistics RPC (first/last seen, largest tx, counts)
- Add collapsible statistics section in Address page (lazy-loaded)
- Support Bitcoin address search in search bar
- Improve endpoint settings UI with connection indicator
- Remove redundant ConnectionStatus component
- Add parallel block reading during historical indexing using rayon
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add rich address types display with script type badges
- Add scriptType.ts utility to detect Bitcoin script types from hex:
P2PKH, P2SH, P2WPKH, P2WSH, P2TR, P2PK, OP_RETURN, P2MS
- Add ScriptTypeBadge component with color-coded badges for each type
- Add OpReturnData component to decode OP_RETURN as readable text
- Update TransactionDetail to show script type badges on outputs
- Update AddressView to show script type badges on UTXOs
- Add build script to shared package for TypeScript project references
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Sankey diagram for transaction flow visualization
- Create TransactionSankey component with pure SVG rendering
- Display inputs on left, outputs on right with curved flow paths
- Show script type badges (P2PKH, P2SH, SegWit, etc.) on outputs
- Support hover highlighting to trace flow from specific inputs
- Handle coinbase transactions with distinct styling
- Add legend explaining node types (input, output, coinbase, OP_RETURN)
- Integrate into TransactionDetail page between header and inputs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix transaction parsing for previous_output format
The RPC returns previous_output as a string "txid:vout" but the
TypeScript types expected an object {txid, vout}. Add transformation
layer in blockchain API to parse the string format into objects.
This fixes the transaction detail page and Sankey diagram which
were broken when accessing inp.previous_output.txid on a string.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Make transaction Sankey diagram more compact
- Reduce SVG dimensions (500x250 max instead of 700x300+)
- Smaller node widths, gaps, and minimum heights
- Compact padding and font sizes
- Smaller legend with abbreviated labels
- Add max-w-lg to constrain width on large screens
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Widen Sankey diagram nodes to show more of txid
- Increase SVG width from 500 to 600
- Increase node width from 100 to 150
- Show more txid characters (12...6 instead of 8...8)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Increase Sankey diagram node heights for better readability
- Increase minimum node height from 24px to 36px
- Increase node gap from 4px to 6px
- Simplify height calculation to ensure all nodes fit content
- Dynamic SVG height based on number of nodes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Use fixed node height with independent centering per side
- Each node has fixed 36px height regardless of count
- Input and output sides center independently
- SVG height adapts to the taller side
- Simpler, more predictable layout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Make Sankey node heights adaptive to available space
- Target height of 180px for the diagram
- Node heights adapt: 36px min to 60px max
- 1 input = 60px tall, 2 outputs = ~71px each
- More nodes = smaller nodes (down to 36px min)
- Each side calculates independently
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add top padding for labels in Sankey diagram
Reserve 28px at top for "Inputs" and "Outputs" labels,
then center nodes in the remaining space below.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Enhance transaction detail with rich metadata and output spending status
- Add output spending status API and display in TransactionSankey
- Show spent/unspent badges with color coding (red/green)
- Display clickable link to spending transaction with vin index
- Track intra-batch spending in indexer for correct status
- Enrich transaction detail page with new fields:
- Size/Virtual Size and Weight (estimated from tx data)
- Total Input value (fetched from previous outputs)
- Fee and Fee Rate (sat/vB) calculated from inputs - outputs
- SegWit/Legacy badge with distinct styling
- RBF enabled/disabled indicator
- Add witness data display in inputs section
- Collapsible witness items with count
- Sequence shown in hex with RBF indicator
- Improve TransactionSankey component:
- Wider nodes (290px) to fit all content
- Dynamic height based on node count
- Input values passed through for flow visualization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add balance history chart and improve block page layout
- Add BalanceHistoryChart component using recharts library
- Display balance over time on address detail page
- Properly handle same-block transactions by sorting receives before sends
- Move Coinbase badge after txid in block page for better alignment
- Add recharts dependency to explorer package
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Optimize indexer batch updates and improve node startup reliability
- Use temporary table for batch UPDATE of spent outputs, reducing ~2000
individual UPDATE statements per block to ~21 queries (bulk insert + single
UPDATE with JOIN)
- Move historical indexing from Indexer::new() to run() to avoid blocking
RPC server startup
- Add loop to catch up until fully synced before subscribing to block
notifications, eliminating buffered notification concerns
- Track last_indexed height properly during live sync including reorgs
- Add title attribute for full txid on hover in TransactionSankey
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add P2PK address support and enhance dashboard with miner info
- Add P2PK (Pay-to-Public-Key) script decoding in both RPC and indexer
- Handle compressed (35 bytes) and uncompressed (67 bytes) P2PK scripts
- Convert P2PK to equivalent P2PKH addresses using Hash160
- Enhance Dashboard with card-style Recent Blocks display
- Show miner address (clickable link to address page)
- Display block reward in BTC
- Parallel block fetching for better performance
- Relative time display (e.g., "5m ago")
- Add subtle indexer sync status indicator
- Show as stat card when indexing (progress percentage)
- Small badge on Address page header when syncing
- Remove unused imports and format helpers
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Run indexer on dedicated thread to avoid blocking main runtime
SQLite operations via sqlx use spawn_blocking internally, which can
saturate the main tokio runtime's blocking thread pool during heavy
indexing. This caused the indexer to fall behind block import.
- Add `run_on_dedicated_thread()` method that spawns a new OS thread
with its own single-threaded tokio runtime
- Change `run()` from public async to private async
- Update run.rs to use the new dedicated thread approach
This isolates the indexer's I/O from the main async runtime, ensuring
block import, networking, and RPC remain responsive while the indexer
runs at full speed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Optimize spent output updates using direct PK lookups
Replace temp table + correlated subquery approach with direct PK-indexed
UPDATE statements for marking spent outputs. The correlated subqueries
become slow as the outputs table grows, while direct PK lookups remain
fast due to the (txid, vout) primary key index.
Benchmark results (blocks per second):
- 10K blocks: 5468 → 5725 (+5%)
- 50K blocks: 2426 → 2966 (+22%)
- 100K blocks: 1021 → 1375 (+35%)
- 110K blocks: 813 → 1120 (+38%)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove quotes from indexer progress log values
Use Display formatting (%) instead of Debug formatting for percent
and blocks_per_sec fields in tracing::info! calls. This produces
cleaner log output without quotes around these values.
Before: percent="45.6%" blocks_per_sec="1127"
After: percent=45.6% blocks_per_sec=1127
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add tmp/ to gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Refactor: move imports to top and use to_core_arg() for network
- Move std::collections::{HashMap, HashSet} import to top of file in db.rs
- Replace network match blocks with network.to_core_arg() in both files
- Move difficulty_from_bits to standalone function in blockchain.rs
- Move SaturatedConversion import to top of file
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add TxoutType::script_type() and reuse solve() for script parsing
- Add script_type() method to TxoutType returning Bitcoin Core compatible
type names (pubkeyhash, scripthash, witness_v0_keyhash, etc.)
- Re-export solve and TxoutType from subcoin-script crate root
- Replace manual script type detection in rawtx.rs with solve().script_type()
- Replace try_decode_p2pk() in blockchain.rs with solve() + TxoutType::PubKey
- Remove ~45 lines of duplicated script parsing logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove unnecessary re-exports and fix clippy warnings
- Remove pub re-exports of Address, AddressApiServer, and BitcoinNetwork
from subcoin-rpc (unused by external consumers)
- Add #[allow(clippy::type_complexity)] to functions with complex tuple
types in subcoin-indexer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* ci: add disk space cleanup to clippy job
The clippy job was failing due to disk space exhaustion when building
librocksdb-sys. Add the same disk space cleanup step that test and
build jobs already have.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>1 parent ed8438e commit 9999efc
File tree
76 files changed
+8991
-447
lines changed- .github/workflows
- crates
- subcoin-indexer
- src
- subcoin-network/src
- sync
- strategy
- subcoin-node
- src
- commands
- subcoin-rpc-bitcoind
- src
- subcoin-rpc
- src
- subcoin-script/src
- js
- packages
- explorer
- src
- components
- contexts
- pages
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
76 files changed
+8991
-447
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
59 | 70 | | |
60 | 71 | | |
61 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
62 | 63 | | |
63 | 64 | | |
64 | 65 | | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
68 | 70 | | |
| 71 | + | |
69 | 72 | | |
70 | 73 | | |
71 | 74 | | |
| |||
138 | 141 | | |
139 | 142 | | |
140 | 143 | | |
| 144 | + | |
141 | 145 | | |
142 | 146 | | |
143 | 147 | | |
| |||
0 commit comments