- Add Prometheus metrics for marketplace API throughput and error rates with new dashboard panels - Implement confidential transaction models with encryption support and access control - Add key management system with registration, rotation, and audit logging - Create services and registry routers for service discovery and management - Integrate ZK proof generation for privacy-preserving receipts - Add metrics instru
323 lines
10 KiB
Markdown
323 lines
10 KiB
Markdown
# explorer-web.md
|
||
Chain Explorer (blocks · tx · receipts)
|
||
|
||
## 0) Purpose
|
||
A lightweight, fast, dark-themed web UI to browse a minimal AITBC blockchain:
|
||
- Latest blocks & block detail
|
||
- Transaction list & detail
|
||
- Address detail (balance, nonce, tx history)
|
||
- Receipt / logs view
|
||
- Simple search (block #, hash, tx hash, address)
|
||
|
||
MVP reads from **blockchain-node** (HTTP/WS API).
|
||
No write operations.
|
||
|
||
---
|
||
|
||
## 1) Tech & Conventions
|
||
- **Pure frontend** (no backend rendering): static HTML + JS modules + CSS.
|
||
- **No frameworks** (keep it portable and fast).
|
||
- **Files split**: HTML, CSS, JS in separate files (user preference).
|
||
- **ES Modules** with strict typing via JSDoc or TypeScript (optional).
|
||
- **Dark theme** with orange/ice accents (brand).
|
||
- **No animations** unless explicitly requested.
|
||
- **Time format**: UTC ISO + relative (e.g., “2m ago”).
|
||
|
||
---
|
||
|
||
## 2) Folder Layout (within workspace)
|
||
```
|
||
explorer-web/
|
||
├─ public/
|
||
│ ├─ index.html # routes: / (latest blocks)
|
||
│ ├─ block.html # /block?hash=... or /block?number=...
|
||
│ ├─ tx.html # /tx?hash=...
|
||
│ ├─ address.html # /address?addr=...
|
||
│ ├─ receipts.html # /receipts?tx=...
|
||
│ ├─ 404.html
|
||
│ ├─ assets/
|
||
│ │ ├─ logo.svg
|
||
│ │ └─ icons/*.svg
|
||
│ ├─ css/
|
||
│ │ ├─ base.css
|
||
│ │ ├─ layout.css
|
||
│ │ └─ theme-dark.css
|
||
│ └─ js/
|
||
│ ├─ config.js # API endpoint(s)
|
||
│ ├─ api.js # fetch helpers
|
||
│ ├─ store.js # simple state cache
|
||
│ ├─ utils.js # formatters (hex, time, numbers)
|
||
│ ├─ components/
|
||
│ │ ├─ header.js
|
||
│ │ ├─ footer.js
|
||
│ │ ├─ searchbox.js
|
||
│ │ ├─ block-table.js
|
||
│ │ ├─ tx-table.js
|
||
│ │ ├─ pager.js
|
||
│ │ └─ keyvalue.js
|
||
│ ├─ pages/
|
||
│ │ ├─ home.js # latest blocks + mempool/heads
|
||
│ │ ├─ block.js
|
||
│ │ ├─ tx.js
|
||
│ │ ├─ address.js
|
||
│ │ └─ receipts.js
|
||
│ └─ vendors/ # (empty; we keep it native for now)
|
||
├─ docs/
|
||
│ └─ explorer-web.md # this file
|
||
└─ README.md
|
||
```
|
||
|
||
---
|
||
|
||
## 3) API Contracts (read-only)
|
||
Assume **blockchain-node** exposes:
|
||
|
||
### 3.1 REST (HTTP)
|
||
- `GET /api/chain/head` → `{ number, hash, timestamp }`
|
||
- `GET /api/blocks?limit=25&before=<blockNumber>` → `[{number,hash,parentHash,timestamp,txCount,miner,size,gasUsed}]`
|
||
- `GET /api/block/by-number/:n` → `{ ...fullBlock }`
|
||
- `GET /api/block/by-hash/:h` → `{ ...fullBlock }`
|
||
- `GET /api/tx/:hash` → `{ hash, from, to, nonce, value, fee, gas, gasPrice, blockHash, blockNumber, timestamp, input }`
|
||
- `GET /api/address/:addr` → `{ address, balance, nonce, txCount }`
|
||
- `GET /api/address/:addr/tx?limit=25&before=<blockNumber>` → `[{hash,blockNumber,from,to,value,fee,timestamp}]`
|
||
- `GET /api/tx/:hash/receipt` → `{ status, gasUsed, logs: [{address, topics:[...], data, index}], cumulativeGasUsed }`
|
||
- `GET /api/search?q=...`
|
||
- Accepts block number, block hash, tx hash, or address
|
||
- Returns a typed result: `{ type: "block"|"tx"|"address" , key: ... }`
|
||
|
||
### 3.2 WebSocket (optional, later)
|
||
- `ws://.../api/stream/heads` → emits new head `{number,hash,timestamp}`
|
||
- `ws://.../api/stream/mempool` → emits tx previews `{hash, from, to, value, timestamp}`
|
||
|
||
> If the node isn’t ready, create a tiny mock server (FastAPI) consistent with these shapes (already planned in other modules).
|
||
|
||
---
|
||
|
||
## 4) Pages & UX
|
||
|
||
### 4.1 Header (every page)
|
||
- Left: logo + “AITBC Explorer”
|
||
- Center: search box (accepts block#, block/tx hash, address)
|
||
- Right: network tag (e.g., “Local Dev”) + head block# (live)
|
||
|
||
### 4.2 Home `/`
|
||
- **Latest Blocks** (table)
|
||
- columns: `#`, `Hash (short)`, `Tx`, `Miner`, `GasUsed`, `Time`
|
||
- infinite scroll / “Load older”
|
||
- (optional) **Mempool feed** (compact list, toggleable)
|
||
- Empty state: helpful instructions + sample query strings
|
||
|
||
### 4.3 Block Detail `/block?...`
|
||
- Top summary (KeyValue component)
|
||
- `Number, Hash, Parent, Miner, Timestamp, Size, GasUsed, Difficulty?`
|
||
- Transactions table (paginated)
|
||
- “Navigate”: Parent ↖, Next ↗, View in raw JSON (debug)
|
||
|
||
### 4.4 Tx Detail `/tx?hash=...`
|
||
- Summary: `Hash, Status, Block, From, To, Value, Fee, Nonce, Gas(gasPrice)`
|
||
- Receipt section (logs rendered as topics/data, collapsible)
|
||
- Input data: hex preview + decode attempt (if ABI registry exists – later)
|
||
|
||
### 4.5 Address `/address?addr=...`
|
||
- Summary: `Address, Balance, Nonce, TxCount`
|
||
- Transactions list (sent/received filter)
|
||
- (later) Token balances when chain supports it
|
||
|
||
### 4.6 Receipts `/receipts?tx=...`
|
||
- Focused receipts + logs view with copy buttons
|
||
|
||
### 4.7 404
|
||
- Friendly message + search
|
||
|
||
---
|
||
|
||
## 5) Components (JS modules)
|
||
- `header.js` : builds header + binds search submit.
|
||
- `searchbox.js` : debounced input, detects type (see utils).
|
||
- `block-table.js` : render rows, short-hash, time-ago.
|
||
- `tx-table.js` : similar render with direction arrows.
|
||
- `pager.js` : simple “Load more” with event callback.
|
||
- `keyvalue.js` : `<dl>` key/value grid for details.
|
||
- `footer.js` : version, links.
|
||
|
||
---
|
||
|
||
## 6) Utils
|
||
- `formatHexShort(hex, bytes=4)` → `0x1234…abcd`
|
||
- `formatNumber(n)` with thin-space groupings
|
||
- `formatValueWei(wei)` → AIT units when available (or plain wei)
|
||
- `timeAgo(ts)` + `formatUTC(ts)`
|
||
- `parseQuery()` helpers for `?hash=...`
|
||
- `detectSearchType(q)`:
|
||
- `0x` + 66 chars → tx/block hash
|
||
- numeric → block number
|
||
- `0x` + 42 → address
|
||
- fallback → “unknown”
|
||
|
||
---
|
||
|
||
## 7) State (store.js)
|
||
- `state.head` (number/hash/timestamp)
|
||
- `state.cache.blocks[number] = block`
|
||
- `state.cache.txs[hash] = tx`
|
||
- `state.cache.address[addr] = {balance, nonce, txCount}`
|
||
- Simple in-memory LRU eviction (optional).
|
||
|
||
---
|
||
|
||
## 8) Styling
|
||
- `base.css`: resets, typography, links, buttons, tables.
|
||
- `layout.css`: header/footer, grid, content widths (max 960px desktop).
|
||
- `theme-dark.css`: colors:
|
||
- bg: `#0b0f14`, surface: `#11161c`
|
||
- text: `#e6eef7`
|
||
- accent-orange: `#ff8a00`
|
||
- accent-ice: `#a8d8ff`
|
||
- Focus states visible. High contrast table rows on hover.
|
||
|
||
---
|
||
|
||
## 9) Error & Loading UX
|
||
- Loading spinners (minimal).
|
||
- Network errors: inline banner with retry.
|
||
- Empty: clear messages & how to search.
|
||
|
||
---
|
||
|
||
## 10) Security & Hardening
|
||
- Treat inputs as untrusted.
|
||
- Only GETs; block any attempt to POST.
|
||
- Strict `Content-Security-Policy` sample (for hosting):
|
||
- `default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; connect-src 'self' https://blockchain-node.local;`
|
||
- Avoid third-party CDNs.
|
||
|
||
---
|
||
|
||
## 11) Test Plan (manual first)
|
||
1. Home loads head + 25 latest blocks.
|
||
2. Scroll/pager loads older batches.
|
||
3. Block search by number + by hash.
|
||
4. Tx search → detail + receipt.
|
||
5. Address search → tx list.
|
||
6. Error states when node is offline.
|
||
7. Timezones: display UTC consistently.
|
||
|
||
---
|
||
|
||
## 12) Dev Tasks (Windsurf order of work)
|
||
1. **Scaffold** folders & empty files.
|
||
2. Implement `config.js` with `API_BASE`.
|
||
3. Implement `api.js` (fetch JSON + error handling).
|
||
4. Build `utils.js` (formatters + search detect).
|
||
5. Build `header.js` + `footer.js`.
|
||
6. Home page: blocks list + pager.
|
||
7. Block detail page.
|
||
8. Tx detail + receipts.
|
||
9. Address page with tx list.
|
||
10. 404 + polish (copy buttons, tiny helpers).
|
||
11. CSS pass (dark theme).
|
||
12. Final QA.
|
||
|
||
---
|
||
|
||
## 13) Mock Data (for offline dev)
|
||
Place under `public/js/vendors/mock.js` (opt-in):
|
||
- Export functions that resolve Promises with static JSON fixtures in `public/mock/*.json`.
|
||
- Toggle via `config.js` flag `USE_MOCK=true`.
|
||
|
||
---
|
||
|
||
## 14) Minimal HTML Skeleton (example: index.html)
|
||
```html
|
||
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||
<title>AITBC Explorer</title>
|
||
<link rel="stylesheet" href="./css/base.css" />
|
||
<link rel="stylesheet" href="./css/layout.css" />
|
||
<link rel="stylesheet" href="./css/theme-dark.css" />
|
||
</head>
|
||
<body>
|
||
<header id="app-header"></header>
|
||
<main id="app"></main>
|
||
<footer id="app-footer"></footer>
|
||
<script type="module">
|
||
import { renderHeader } from './js/components/header.js';
|
||
import { renderFooter } from './js/components/footer.js';
|
||
import { renderHome } from './js/pages/home.js';
|
||
renderHeader(document.getElementById('app-header'));
|
||
renderFooter(document.getElementById('app-footer'));
|
||
renderHome(document.getElementById('app'));
|
||
</script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
---
|
||
|
||
## 15) config.js (example)
|
||
```js
|
||
export const CONFIG = {
|
||
API_BASE: 'http://localhost:8545', // adapt to blockchain-node
|
||
USE_MOCK: false,
|
||
PAGE_SIZE: 25,
|
||
NETWORK_NAME: 'Local Dev',
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 16) API Helpers (api.js — sketch)
|
||
```js
|
||
import { CONFIG } from './config.js';
|
||
|
||
async function jget(path) {
|
||
const res = await fetch(`${CONFIG.API_BASE}${path}`, { method: 'GET' });
|
||
if (!res.ok) throw new Error(`HTTP ${res.status}: ${path}`);
|
||
return res.json();
|
||
}
|
||
|
||
export const api = {
|
||
head: () => jget('/api/chain/head'),
|
||
blocks: (limit, before) => jget(`/api/blocks?limit=${limit}&before=${before ?? ''}`),
|
||
blockByNo: (n) => jget(`/api/block/by-number/${n}`),
|
||
blockByHash: (h) => jget(`/api/block/by-hash/${h}`),
|
||
tx: (hash) => jget(`/api/tx/${hash}`),
|
||
receipt: (hash) => jget(`/api/tx/${hash}/receipt`),
|
||
address: (addr) => jget(`/api/address/${addr}`),
|
||
addressTx: (addr, limit, before) => jget(`/api/address/${addr}/tx?limit=${limit}&before=${before ?? ''}`),
|
||
search: (q) => jget(`/api/search?q=${encodeURIComponent(q)}`),
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 17) Performance Checklist
|
||
- Use pagination/infinite scroll (no huge payloads).
|
||
- Cache recent blocks/tx in-memory (store.js).
|
||
- Avoid layout thrash: table builds via DocumentFragment.
|
||
- Defer non-critical fetches (e.g., mempool).
|
||
- Keep CSS small and critical.
|
||
|
||
---
|
||
|
||
## 18) Deployment
|
||
- Serve `public/` via Nginx under `/explorer/` or own domain.
|
||
- Set correct `connect-src` in CSP to point to blockchain-node.
|
||
- Ensure CORS on blockchain-node for the explorer origin (read-only).
|
||
|
||
---
|
||
|
||
## 19) Roadmap (post-MVP)
|
||
- Live head updates via WS.
|
||
- Mempool stream view.
|
||
- ABI registry + input decoding.
|
||
- Token balances (when chain supports).
|
||
- Export to CSV / JSON for tables.
|
||
- Theming switch (dark/light).
|
||
|
||
---
|
||
|