Event listening & indexing ke MySQL
Aplikasi produksi hampir tidak pernah membaca riwayat transaksi langsung dari node saat pengguna membuka halaman. Pola standarnya: proses latar belakang mendengarkan event, mencatatnya ke database relasional, dan halaman aplikasi cukup query SQL biasa.
Intisari
- Event log tidak tersimpan di storage kontrak (Fase 1) — mengambilnya lagi harus lewat
eth_getLogs, yang lambat untuk query berulang dari banyak pengguna sekaligus. - Pola standarnya: proses indexer terpisah mendengarkan event baru, menyimpannya ke tabel MySQL lokal — aplikasi utama cukup
SELECTdari tabel itu, bukan bertanya ke blockchain setiap request. - Idempotensi wajib: kunci baris unik pada
(tx_hash, log_index), bukan cumatx_hash— satu transaksi bisa memuat banyak event. - Simpan block terakhir yang berhasil diindeks supaya proses bisa dilanjutkan dari titik terakhir setelah restart, bukan dari awal.
- Tunggu beberapa konfirmasi block sebelum menganggap event final — block yang sangat baru masih punya kemungkinan kecil di-reorg (digantikan rantai lain), meski kecil di Ethereum pasca-Merge.
Kenapa tidak query blockchain langsung tiap request
Menampilkan "riwayat transaksi" pengguna di halaman web dengan memanggil eth_getLogs setiap
kali halaman dibuka akan lambat (satu panggilan RPC ekstra per request), rawan kena rate limit provider,
dan tidak bisa di-JOIN dengan data lain di database-mu (nama pengguna, status KYC, dst). Solusi
standarnya sama dengan pola caching pada umumnya: proses latar belakang menyalin data relevan ke database
lokal, aplikasi utama membaca dari salinan itu.
Skema tabel indexing
CREATE TABLE gold_transactions (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tx_hash CHAR(66) NOT NULL,
log_index INT UNSIGNED NOT NULL,
block_number BIGINT UNSIGNED NOT NULL,
event_name VARCHAR(32) NOT NULL,
dari_alamat CHAR(42) NULL,
ke_alamat CHAR(42) NULL,
jumlah_gram DECIMAL(36, 0) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uq_log (tx_hash, log_index)
);
CREATE TABLE indexer_state (
kontrak VARCHAR(42) PRIMARY KEY,
last_block BIGINT UNSIGNED NOT NULL
);
Kenapa UNIQUE KEY (tx_hash, log_index), bukan tx_hash saja. Satu
transaksi yang memanggil mintGold() bisa memicu lebih dari satu event dalam satu eksekusi
(mis. Transfer bawaan ERC-20 dan EmasDiterbitkan kustom). Menjadikan
tx_hash saja sebagai unique key akan membuat baris kedua ditolak sebagai "duplikat" padahal
keduanya event yang sah dan berbeda.
Indexer di web3j: Flowable event
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
EthFilter filter = new EthFilter(
DefaultBlockParameter.valueOf(BigInteger.valueOf(lastBlockTersimpan)),
DefaultBlockParameterName.LATEST,
alamatKontrak
);
kontrak.emasDiterbitkanEventFlowable(filter).subscribe(event -> {
// Idempoten: INSERT ... ON DUPLICATE KEY UPDATE, atau cek exists dulu
simpanKeMySQL(
event.log.getTransactionHash(),
event.log.getLogIndex().intValue(),
event.log.getBlockNumber(),
"EmasDiterbitkan",
null,
event.ke,
event.gram
);
updateLastBlock(event.log.getBlockNumber());
}, error -> log.error("Indexer error, akan retry dari last_block tersimpan", error));
Polling vs subscription — dan kenapa polling lebih aman untuk pemula
Polling (eth_getLogs berkala) | Subscription (WebSocket) | |
|---|---|---|
| Kompleksitas | Rendah — cron job/scheduled task biasa | Lebih tinggi — perlu kelola koneksi persisten & reconnect |
| Latensi | Sesuai interval polling (mis. tiap 15 detik) | Nyaris real-time |
| Tahan restart proses | Ya — tinggal lanjut dari last_block | Butuh penanganan tambahan agar tidak kehilangan event saat reconnect |
| Provider gratis mendukung? | Hampir selalu | Sering dibatasi paket berbayar |
Konfirmasi block: menunggu sebelum menganggap final
Block terbaru masih bisa "berubah pikiran". Dalam kondisi jaringan tertentu, block yang baru
saja ditambang bisa digantikan block lain di cabang yang berbeda (reorg) — meski di Ethereum
pasca-Merge kemungkinannya sangat kecil untuk block yang sudah finalized. Praktik aman: proses
indexer menunggu event berada beberapa block di belakang latest (mis. 12 block, atau tunggu
status finalized lewat eth_getBlockByNumber dengan tag finalized)
sebelum menuliskannya sebagai baris permanen di database — supaya tabel gold_transactions
tidak pernah perlu di-rollback.
Latihan: buat tabel gold_transactions dan indexer_state di MySQL
lokal. Tulis satu skrip Java (atau PHP dengan polling eth_getLogs manual lewat web3.php)
yang membaca event EmasDiterbitkan dari kontrak testnet-mu sejak block deploy, menuliskannya
idempoten ke tabel, lalu jalankan skripnya dua kali berturut-turut — pastikan baris tidak terduplikasi
pada jalankan kedua.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.