Belajar Solidity - Storage, Memory & Gas Optimization
Episode 6 of 23

Belajar Solidity - Storage, Memory & Gas Optimization

Membedah layout storage Solidity berbasis slot 32-byte, teknik packing untuk menempatkan beberapa variabel dalam satu slot, strategi menghindari SSTORE yang mahal, serta kapan memakai immutable dan constant untuk menekan biaya gas

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 5 kalian menguasai fungsi, modifier, dan visibility, pada episode ini kita membahas topik yang paling berpengaruh pada biaya: bagaimana EVM menyimpan state dan bagaimana memilih tipe data agar murah.

Mengapa episode ini penting? Karena di blockchain, efisiensi = uang. Dua kontrak dengan fungsi identik bisa berbeda biaya deploy maupun biaya transaksi berkali-kali lipat hanya karena cara state variable disusun. Di dunia kerja, optimasi gas adalah pembeda antara kontrak yang layak dipakai dan kontrak yang terlalu mahal untuk dioperasikan.

Storage Layout: Slot 32-Byte

Storage adalah array besar dari slot berukuran 32 byte yang berurutan. State variable ditempatkan secara berurutan mulai dari slot 0, dan packing otomatis terjadi: variabel-variabel kecil yang totalnya masih 32 byte akan digabung dalam satu slot.

solidity
uint256 public a;      // slot 0 (full 32 byte)
address public b;      // slot 1 (20 byte)
bool public c;         // slot 1 (1 byte)  -> menumpuk dengan b
uint128 public d;      // slot 1 (16 byte) -> masih muat di slot 1

Urutan di atas menempatkan 4 variabel hanya dalam 2 slot. Bandingkan jika ditulis serampangan:

solidity
bool public c;         // slot 0
address public b;      // slot 0 (muat)
uint256 public a;      // slot 1 (full)
uint128 public d;      // slot 2 (setengah terisi)

Hasilnya 3 slot — lebih boros. Setiap slot terisi (SSTORE) saat deploy membayar biaya, jadi packing yang baik menghemat biaya deploy dan pembacaan.

Teknik Packing Struct

Packing yang disengaja paling terlihat pada struct:

solidity
struct TokenInfo {
    uint128 supply;      // 16 byte
    uint128 maxSupply;   // 16 byte -> satu slot dengan supply
    address owner;       // 20 byte
    bool paused;         // 1 byte  -> satu slot dengan owner
}

TokenInfo memakan 2 slot berkat urutan yang rapi. Jika bool paused diletakkan di antara uint128 dan address, hasilnya bisa 3 slot. Aturannya: kelompokkan variabel berukuran kecil berdekatan agar muat dalam satu slot, dan utamakan uint256/besar di slot sendiri.

Tip

Kompiler memberi peringatan "Unused variable" atau rekomendasi layout lewat optimizer; di toolchain modern (Hardhat/Foundry), kalian juga bisa memakai plugin untuk menampilkan storage layout aktual kontrak kalian dan mengecek jumlah slot yang dipakai.

Layout Mapping dan Array

mapping dan array dinamis tidak menyimpan isinya di slot berurutan:

  • mapping: slot keccak256(key . slotIndex) untuk setiap key. Artinya isi mapping tidak bisa di-enumerasi — konsisten dengan apa yang kita bahas di episode 4.
  • array dinamis: slot index menyimpan panjangnya, isi dimulai dari keccak256(slotIndex).
  • array fixed-size: disimpan inline berurutan seperti state variable.

Implikasi praktis: mapping itu murah untuk lookup acak, tapi jika kalian butuh urutan atau iterasi, simpan array terpisah.

Menghindari SSTORE yang Mahal

Menulis storage (SSTORE) adalah operasi termahal. Beberapa strategi klasik:

  1. Baca dulu, tulis jika berubah — hindari menulis nilai yang sama.
  2. Bekerja di memory lalu tulis sekali — misalnya memproses loop di memory, simpan hasil akhir.
  3. Gunakan event untuk riwayat — jika data hanya butuh dibaca frontend dan tidak perlu dibaca kontrak lain, simpan di event, bukan storage.
  4. immutable dan constant — nilai yang ditentukan sekali dan tak berubah bisa disimpan langsung di bytecode (constant) atau di-deploy sekali (immutable), tanpa memakan slot.
solidity
uint256 public constant MAX_SUPPLY = 1_000_000;
address public immutable deployer;
 
constructor() {
    deployer = msg.sender;
}

MAX_SUPPLY dimasukkan ke bytecode, dan deployer di-set sekali saat deploy — keduanya tidak memakai slot storage, sehingga getter-nya murah dan deploy lebih ringan.

solidity
function update(uint256 _value) external {
    uint256 current = stored;      // 1x SLOAD
    if (current == _value) return; // skip SSTORE jika sama
    stored = _value;               // 1x SSTORE
}

Common Pitfall

  • Salah urutan struct — packing tidak efektif, slot bertambah.
  • Menulis state di dalam loop — setiap iterasi memicu SSTORE; pindahkan penulisan ke akhir.
  • Memakai string/bytes dinamis tanpa perlu — data dinamis disimpan terpisah dan lebih mahal dibaca.
  • Get old value tidak diperlukan — menghapus storage (set ke 0) memberikan refund gas, tapi jangan diandalkan sebagai strategi utama.

Penutup

Inti yang harus dibawa pulang:

  • Storage adalah array slot 32-byte; variabel kecil di-packing otomatis ke slot yang sama.
  • Urutkan struct/state variable agar packing efisien — hemat deploy dan akses.
  • mapping tersebar via keccak256, tidak iterable; array fixed-size disimpan inline.
  • Hindari SSTORE berulang: baca-tulis sekali, pakai event untuk riwayat, dan manfaatkan immutable/constant.

Di episode 7 selanjutnya kita akan membahas inheritance, abstract contract, dan interface — mewarisi logika dengan is, menulis kontrak abstrak, dan berinteraksi dengan kontrak lain lewat interface seperti ERC-20 dan ERC-721. Pastikan kalian nyaman dengan layout storage, karena pola ini dipakai di hampir semua kontrak produksi!

Belajar Solidity - Storage, Memory & Gas Optimization | Belajar Solidity