← Semua pembelajaran / Blockchain Nol → RWA
Fase 3 · Integrasi Backend Java & PHP

Read vs write — call gratis vs transaksi berbayar

Ini pembagian paling mendasar saat backend berbicara ke smart contract — dan salah memperlakukan salah satunya seperti yang lain adalah sumber bug arsitektur paling umum bagi pendatang baru.

Intisari

  • Read (fungsi view/pure): dipanggil lewat eth_call, tidak butuh gas, tidak butuh private key, tidak butuh menunggu block — hasilnya instan, seperti query database biasa.
  • Write (fungsi yang mengubah state): butuh transaksi yang ditandatangani private key, dikirim ke mempool, menunggu masuk block, dan berbayar gas.
  • Read tidak pernah gagal karena "kehabisan gas" — ia mensimulasikan eksekusi secara lokal di node tanpa benar-benar mengubah apa pun.
  • Write butuh nonce yang benar dan gas price yang memadai; salah satunya bisa membuat transaksi tertahan lama di mempool atau gagal total.
  • Arsitektur backend yang sehat: read bisa dipanggil sinkron dari request HTTP biasa; write harus asinkron — kirim transaksi, simpan hash-nya, lalu proses terpisah yang memantau konfirmasinya (dibahas di Fase 5).

Dua jalur yang terlihat mirip, perilakunya sangat berbeda

Read (eth_call)Write (eth_sendRawTransaction)
Butuh private key?TidakYa — untuk menandatangani
Butuh gas/biaya?TidakYa
Waktu responsInstan (milidetik)Detik sampai menit — menunggu block
Bisa mengubah state?Tidak, sekalipun fungsinya mencobaYa
Analog Web2SELECT ke read-replicaINSERT/UPDATE lewat antrean job

Kenapa read bisa gratis: eth_call menjalankan bytecode fungsi secara lokal di node yang kamu tanya, memakai state block terkini, lalu membuang hasil eksekusinya begitu selesai — tidak pernah disiarkan ke jaringan, tidak pernah masuk block, tidak pernah butuh konsensus. Ini kenapa fungsi view/pure di Solidity ditolak compiler kalau mencoba menulis state: compiler tahu hasil tulisannya tidak akan pernah benar-benar tersimpan lewat jalur ini.

Read di web3j — sinkron, seperti query biasa

// Wrapper Java digenerate dari ABI kontrak (dibahas di materi berikutnya)
GoldToken kontrak = GoldToken.load(alamatKontrak, web3j, credentials, gasProvider);

BigInteger saldo = kontrak.balanceOf(alamatPengguna).send();
// .send() di sini tidak mengirim transaksi ke jaringan — nama method
// generik web3j untuk "eksekusi panggilan dan tunggu hasilnya", dipakai
// baik untuk call maupun transaction. Konteksnya (fungsi view atau bukan)
// yang menentukan mana yang sebenarnya terjadi di baliknya.

Write di web3j — asinkron secara alami

TransactionReceipt receipt = kontrak.mintGold(
    alamatPengguna, BigInteger.valueOf(100), "bukti-brankas-001"
).send();   // BLOCKING sampai transaksi masuk block — bisa detik sampai menit

if (receipt.isStatusOK()) {
    System.out.println("Sukses, block: " + receipt.getBlockNumber());
} else {
    System.out.println("Transaksi masuk block tapi REVERT — gas tetap terpakai");
}

Jebakan arsitektur paling umum: memperlakukan write seperti call REST API biasa. Kalau endpoint API-mu memanggil .send() pada fungsi write lalu langsung menunggu hasilnya secara sinkron di dalam siklus request HTTP, pengguna akan menatap loading spinner selama puluhan detik — dan kalau koneksi terputus di tengah jalan, kamu tidak tahu apakah transaksinya sukses, gagal, atau masih tertahan di mempool. Pola yang benar: endpoint API menerima permintaan, mengirim transaksi, langsung mengembalikan transactionHash ke klien, lalu proses terpisah (worker/queue) yang memantau konfirmasinya. Detail penuhnya di Fase 5.

Nonce: kenapa write butuh koordinasi yang tidak dibutuhkan read

Ingat dari Fase 0: tiap transaksi butuh nonce yang urut per akun. Kalau backend-mu mengirim banyak transaksi write dari satu akun service secara paralel tanpa mengelola nonce secara eksplisit, dua request yang datang bersamaan bisa mendapat nonce yang sama — salah satunya pasti ditolak node. Ini konsekuensi langsung yang tidak pernah muncul di jalur read, karena read tidak pernah menyentuh nonce sama sekali.

Latihan: di kontrak GoldToken milikmu (Fase 2), panggil balanceOf() lewat Remix — perhatikan tidak ada dialog konfirmasi MetaMask/gas yang muncul. Lalu panggil mintGold() — perhatikan dialog konfirmasi transaksi muncul. Jelaskan sendiri kenapa Remix (dan wallet mana pun) tahu persis kapan harus meminta konfirmasi dan kapan tidak, berdasarkan keyword view/pure di definisi fungsinya.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.