Files
databisnisid/get_voters.js
T
proitlab c5e30a4785 T1-T5: Python voter fetcher (§V1-9)
- get_voters.py: scan Vexanium voters table (vexcore), retry/paginate,
  filter databisnisid single-vote + stake ≥1000 VEX, store weight verbatim,
  daily-replace SQLite snapshot (owner PK, scanned_at)
- V8/V9 + test_get_voters.py (oracle, §V1-9)
- SPEC.md, AGENTS.md, requirements.txt
2026-08-04 15:56:19 +07:00

99 lines
3.0 KiB
JavaScript

// Ganti dengan nama akun Block Producer Anda di Vexanium
const TARGET_BP = 'databisnisid';
// Menggunakan API dari v2.vexascan.com
const API_NODE = 'https://v2.vexascan.com:2096';
// Fungsi pembantu untuk fetch dengan mekanisme retry (karena node ini kadang timeout)
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response;
} catch (error) {
if (i === maxRetries - 1) throw error;
console.log(`[Warning] Gagal menghubungi node, mencoba lagi... (${i + 1}/${maxRetries})`);
await new Promise(res => setTimeout(res, 2000)); // tunggu 2 detik sebelum retry
}
}
}
async function getVotersForMyBP() {
let myVoters = [];
let lowerBound = '';
let hasMore = true;
let totalScanned = 0;
console.log(`Mulai memindai voters untuk BP: "${TARGET_BP}"...`);
while (hasMore) {
try {
// Menggunakan fetchWithRetry yang sudah kita buat
const response = await fetchWithRetry(`${API_NODE}/v1/chain/get_table_rows`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
json: true,
// PENTING: Di Vexanium, kontrak sistem (untuk tabel voters) adalah vexcore, bukan vexio
code: 'vexcore',
scope: 'vexcore',
table: 'voters',
lower_bound: lowerBound,
limit: 500
})
});
const data = await response.json();
const rows = data.rows || [];
if (rows.length === 0) break;
// Hindari duplikasi elemen pertama saat pagination
if (lowerBound !== '') {
rows.shift();
}
totalScanned += rows.length;
// Saring hanya pemilih yang HANYA mem-vote BP ini (eksklusif 1 vote)
const filtered = rows.filter(voter =>
Array.isArray(voter.producers) &&
voter.producers.length === 1 &&
voter.producers[0] === TARGET_BP
);
myVoters = myVoters.concat(filtered);
hasMore = data.more;
if (hasMore && rows.length > 0) {
lowerBound = rows[rows.length - 1].owner;
}
} catch (error) {
console.error('\nError saat mengambil data:', error.message);
break;
}
}
console.log(`\n=== HASIL AKHIR ===`);
console.log(`Total akun dipindai di jaringan: ${totalScanned}`);
console.log(`Total voters untuk BP [${TARGET_BP}]: ${myVoters.length}`);
// Menampilkan daftar pemilih beserta VEX staked-nya
console.log('\nDaftar Pemilih:');
if (myVoters.length === 0) {
console.log('(Tidak ada pemilih ditemukan untuk BP ini atau scan terhenti di tengah jalan)');
} else {
myVoters.forEach((v, index) => {
// VEX stake disimpan dalam pecahan 1/10000 (4 desimal)
const vexStaked = (v.staked / 10000).toLocaleString('id-ID');
console.log(`${index + 1}. ${v.owner} - Stake: ${vexStaked} VEX`);
});
}
return myVoters;
}
getVotersForMyBP();