T14: penanda vote basi (last_vote dari rasio bobot/stake, filter ?stale=1, VEX_STALE_DAYS)

This commit is contained in:
proitlab committed 2026-08-04 17:05:16 +07:00
1 parent 2b95be3091
commit b0b3ba8ab3
10 files changed
+236 -52

No files matched your search

+5 -4
View File
@@ -7,8 +7,8 @@ Two tools scan the Vexanium blockchain voters table for accounts whose only vote
- Node reference script: `node get_voters.js` (no deps, Node 18+).
- Python tool (production): `./venv/bin/python get_voters.py`. venv is Python 3.12, deps `requests` + `flask` + `python-dotenv` (`requirements.txt`). Install with `./venv/bin/pip install -r requirements.txt`.
- Web dashboard (read-only, reads `voters.db`): production `./venv/bin/gunicorn -c gunicorn.conf.py dashboard:app` → http://127.0.0.1:5000/ (run from repo dir). `gunicorn.conf.py` imports `config` → `.env` honored; `DASH_WORKERS` (default 2) controls workers, `DASH_HOST`/`DASH_PORT` the bind. Dev server (single-process) still works via `./venv/bin/python dashboard.py`. Paged 50/page, sorted `staked DESC`, live owner search (`/api/search`). Data freshness comes from the daily scan run — the dashboard never scans.
- Config: all tunables load from env / `.env` via `config.py` (python-dotenv): `VEX_TARGET_BP`, `VEX_API_NODE`, `VEX_DB_PATH`, `VEX_MIN_STAKED_VEX`, `DASH_PAGE_SIZE`, `DASH_HOST`, `DASH_PORT`, `DASH_WORKERS`. Copy `.env.example` → `.env` to override; `.env` is gitignored. Chain constants (`vexcore`/scope/table) stay hardcoded.
- Syntax check: `node --check get_voters.js`, `./venv/bin/python -m py_compile config.py get_voters.py dashboard.py`.
- Config: all tunables load from env / `.env` via `config.py` (python-dotenv): `VEX_TARGET_BP`, `VEX_API_NODE`, `VEX_DB_PATH`, `VEX_MIN_STAKED_VEX`, `DASH_PAGE_SIZE`, `DASH_HOST`, `DASH_PORT`, `DASH_WORKERS`, `VEX_STALE_DAYS`. Copy `.env.example` → `.env` to override; `.env` is gitignored. Chain constants (`vexcore`/scope/table) stay hardcoded.
- Syntax check: `node --check get_voters.js`, `./venv/bin/python -m py_compile config.py get_voters.py dashboard.py gunicorn.conf.py`.
- Tests (the verification oracles): `./venv/bin/python test_get_voters.py` and `./venv/bin/python test_dashboard.py` must both exit 0. They mock the network / use a temp DB — the live node is too flaky/slow for a full-scan test. Run after touching the relevant file.
## Key facts
@@ -20,14 +20,15 @@ Two tools scan the Vexanium blockchain voters table for accounts whose only vote
- The node sometimes returns `staked` as a string instead of a number — normalize coerces to float (spec §V8).
- The voters table has a sentinel first row (`owner="...........q"`, uint64 0) that must be skipped.
- Authoritative vote weight is `last_vote_weight` (high-precision decimal string) — stored verbatim as TEXT, never float-converted (spec §V6).
- Stale-vote flag (spec §V13): `last_vote` (estimated last re-vote date) is derived at scan time from the Vexanium weight formula `last_vote_weight = staked_raw × 2^(years since 2000)` → `log2(weight / (staked×10000))`. A voter is `stale` when `last_vote` is older than `VEX_STALE_DAYS` (default 28). Filter via `?stale=1`.
## Layout
- `SPEC.md` — spec (goal/constraints/interfaces/invariants/tasks/bug log), in caveman encoding. Build/backprop flow through it.
- `get_voters.py` — production fetcher: scan → filter → SQLite `voters.db` (each run replaces the table = daily snapshot, with `scanned_at`; never appends history).
- `get_voters.py` — production fetcher: scan → filter → SQLite `voters.db` (each run replaces the table = daily snapshot, with `scanned_at` + derived `last_vote`; never appends history).
- `get_voters.js` — reference implementation only.
- `dashboard.py` + `templates/index.html` + `static/style.css` + `static/app.js` — Flask web dashboard; reads `voters.db`, styled per `DESIGN.md`; `app.js` = debounced live owner search (fetch `/api/search`), degrades to the server-side `?q=` GET form if JS is off.
- `config.py` — loads env/`.env` (python-dotenv) → `TARGET_BP`, `API_NODE`, `DB_PATH`, `MIN_STAKED_VEX`, `PAGE_SIZE`, `DASH_HOST`, `DASH_PORT`; shared by get_voters & dashboard.
- `config.py` — loads env/`.env` (python-dotenv) → `TARGET_BP`, `API_NODE`, `DB_PATH`, `MIN_STAKED_VEX`, `PAGE_SIZE`, `DASH_HOST`, `DASH_PORT`, `DASH_WORKERS`, `VEX_STALE_DAYS`; shared by get_voters & dashboard.
- `DESIGN.md` — Bugatti austere style guide; the dashboard's CSS maps its tokens (canvas #000000, hairline #262626, weight 400 everywhere, fonts Saira Condensed / EB Garamond / JetBrains Mono).
- `voters.db` — SQLite output (daily snapshot, gitignored in spirit).