V40-V43: band umur vote (BARU/VALID/KADALUARSA, scan simpan semua umur) → REVOTE = VALID langsung (V42) → tag mint 1-hari + badge VOTE ULANG SEGERA (V43) ; klaim recovery jendela lewat + parse respons dict rows (B7/B8) ; backend mysql test_mariadb ; oracle test_dashboard/distribute/get_voters/mariadb ; images web/scan/dist/claim rebuild + push

This commit is contained in:
proitlab committed 2026-08-07 12:07:34 +07:00
1 parent af9a0291b9
commit 81ec6bdfe7
17 files changed
+914 -148

No files matched your search

+16 -16
View File
@@ -1,7 +1,10 @@
"""Scan tabel voters Vexanium, simpan pemilih BP databisnisid + bobot suara ke SQLite.
Hanya pemilih segar (revote ≤ VEX_STALE_DAYS lalu) yang disimpan — vote basi
dibuang. Berjalan imparsial (repeatable) dan siap dijadwalkan (cron).
Sejak V40 SEMUA pemilih BP dengan last_vote terverifikasi disimpan — termasuk
yang basi (> VEX_STALE_DAYS). Banding/kadaluarsa bukan urusan scan: tampilan
(dashboard) dan pembayaran (distribute) menghitung umur vote saat itu juga.
Hanya pemilih dengan last_vote tak terverifikasi (bobot nol/kosong) yang dibuang.
Berjalan imparsial (repeatable) dan siap dijadwalkan (cron).
"""
import math
@@ -12,7 +15,7 @@ from datetime import datetime, timedelta, timezone
import requests
import db
from config import API_NODE, MIN_STAKED_VEX, TARGET_BP, VEX_STALE_DAYS
from config import API_NODE, MIN_STAKED_VEX, TARGET_BP
# Kontrak & scope sistem Vexanium = vexcore (BUKAN vexio sesuai konvensi EOS)
CODE = 'vexcore'
@@ -105,21 +108,15 @@ def scan_voters():
return rows_all
def _is_stale(last_vote, now):
"""V13: apakah revote terakhir sudah lewat ambang basi (VEX_STALE_DAYS)."""
try:
vote_at = datetime.fromisoformat(last_vote)
except (TypeError, ValueError):
return True
return (now - vote_at) > timedelta(days=VEX_STALE_DAYS)
def normalize(row, now=None):
"""V4/V5/V6/V13: saring ke baris yang relevan, bidang dinormalisasi.
V13: pemilih dengan last_vote tak diketahui atau basi dibuang di sini —
hanya pemilih segar yang berakhir di DB. Estimasi last_vote yang melewati
`now` (unstake tanpa revote → rasio bobot/stake membesar) diklamp ke `now`.
V40: pemilih dengan last_vote basi TIDAK lagi dibuang di sini — semua umur
vote disimpan (tampil/bayar menghitung umur saat query). Yang tetap dibuang:
sentinel "0", bukan BP target, stake < minimum, dan last_vote yang tak bisa
diverifikasi (bobot nol/kosong → tanggal tak diketahui, tak bisa diklasifikasi).
Estimasi last_vote yang melewati `now` (unstake tanpa revote → rasio
bobot/stake membesar) diklamp ke `now`.
"""
if now is None:
now = datetime.now(timezone.utc).replace(tzinfo=None)
@@ -134,7 +131,7 @@ def normalize(row, now=None):
last_vote = derive_last_vote(row.get('last_vote_weight', ''), staked_vex)
if last_vote is not None and last_vote > now.isoformat(timespec='seconds'):
last_vote = now.isoformat(timespec='seconds') # V13: heuristik ⊥ boleh di masa depan
if last_vote is None or _is_stale(last_vote, now): # V13: basi ⊥ disimpan
if last_vote is None: # V13: tanggal tak diketahui → tak dapat diklasifikasi
return None
return {
'owner': owner,
@@ -150,9 +147,12 @@ def persist(rows):
Delegasi ke `db.replace_snapshot` (backend sqlite/mysql):
sqlite DROP+CREATE dalam WAL → pembaca (dashboard multi-worker) tak
terblokir; mysql DELETE+INSERT dalam satu transaksi (MVCC snapshot).
Lalu `db.record_first_seen` (V41): catat kemunculan pertama tiap owner
(idempoten) utk membedakan pemilih BARU vs REVOTE di dashboard.
"""
scanned_at = datetime.now().isoformat(timespec='seconds')
db.replace_snapshot(rows, scanned_at)
db.record_first_seen(rows, scanned_at)
return scanned_at