IPFS & Decentralized Storage — Web3

IPFS & Decentralized Storage IPFS (InterPlanetary File System) adalah protocol peer-to-peer untuk menyimpan dan berbagi file secara terdesentralisasi. Berbeda…

IPFS (InterPlanetary File System) adalah sistem file terdistribusi peer-to-peer yang memakai content addressing: file dicari berdasarkan sidik jari isinya, bukan berdasarkan server tempat ia disimpan. Bayangin minta buku ke teman-teman: kamu gak bilang "buku di rak 3 rumah Raka", tapi "buku yang sidik jarinya X". Siapa pun yang punya salinannya boleh memberikan, dan kamu bisa menghitung ulang sidik jarinya untuk memastikan bukunya gak ditukar. Tapi kalau gak ada satu pun yang menyimpan salinan, bukunya hilang.

🧪 Tebakan cepat: metadata KOPI #1 sudah di IPFS dan tokenURI(1) menunjuk ke sana. Raka mengubah ukuran di metadata itu dari L jadi XL lalu meng-upload ulang. Apakah tokenURI(1) sekarang menunjuk ke isi yang baru? Tebak dulu, jawabannya ada di bagian "Mengganti isi berarti CID baru".

Alamat lokasi vs alamat isi

Di lesson ERC-721, tokenURI(1) adalah https://toko-kaos-raka.test/kopi/1: alamat lokasi. Server itu bisa mati, atau isinya diganti diam-diam, dan pemilik NFT gak bisa tahu. Di IPFS alamatnya adalah CID (Content Identifier), hasil hash dari isi file. Isi sama, CID sama, di komputer mana pun. Ubah satu byte, CID-nya berubah total.

CID: sidik jari isi file

Gambar kaos untuk sertifikat KOPI adalah file SVG 234 byte, kaos-kopi.svg. Raka menghitung CID-nya dengan kubo 0.43.1 (implementasi IPFS dalam Go) secara offline (--offline: gak terhubung ke jaringan, gak ada yang ter-upload):

$ ipfs add --offline --cid-version 1 kaos-kopi.svg
added bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i kaos-kopi.svg
$ ipfs add --offline kaos-kopi.svg
added QmYpJh9o16QHqf8jaoQRxcfMoTgYJVbPZrSnkHaRn33ZkZ kaos-kopi.svg

Yang pertama CIDv1, yang kedua CIDv0 (masih bawaan kubo kalau gak diberi --cid-version 1). Isinya sama, tapi teksnya beda, jadi pilih satu versi dan konsisten. CIDv1 di atas bisa dibongkar:

Bagian Nilai Artinya
multibase b sisanya ditulis base32 huruf kecil
versi 0x01 CIDv1
codec 0x55 raw: isi file apa adanya
multihash 0x12 0x20 + 32 byte SHA-256, panjang 32 byte: 424075df...c2f38dda

Jadi CID = b + base32(01 55 12 20 + sha256(isi file)). Library multiformats menghitung hal yang sama: CID.create(1, raw.code, await sha256.digest(bytes)). Hasilnya cocok persis dengan kubo.

Metadata KOPI di IPFS

Metadata #1 sekarang menunjuk gambarnya dengan ipfs://, bukan URL server. File kopi/1 (393 byte) berisi:

{
  "name": "Kaos Edisi Kopi #1",
  "description": "Sertifikat bernomor Kaos Sablon Kopi edisi terbatas Toko Kaos Raka. Satu dari 100.",
  "image": "ipfs://bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i",
  "attributes": [
    {
      "trait_type": "Ukuran",
      "value": "L"
    },
    {
      "trait_type": "Nomor",
      "value": 1,
      "display_type": "number"
    }
  ]
}

Raka menaruh metadata #1 dan #2 di satu folder kopi/, lalu menambahkan folder itu:

$ ipfs add --offline --cid-version 1 -r kopi
added bafkreie2qgfr2dgxygy3jgx3mvcz6bz66sdri6efobmiqwudwrm6b7daeq kopi/1
added bafkreifeyj4c7uw6zdoh3lqnuwcou4q3zmvkdqmvfyo3k5uizp6iaggype kopi/2
added bafybeifuwwkzdzittkxf5ghlmsq2k6jqasyheos6mb3vgz4l73qcmsgfku kopi

Folder juga punya CID (bafybei..., codec dag-pb), dihitung dari nama dan CID file-file di dalamnya. KaosEdisiKopi cukup mengganti satu baris:

function _baseURI() internal pure override returns (string memory) {
    return "ipfs://bafybeifuwwkzdzittkxf5ghlmsq2k6jqasyheos6mb3vgz4l73qcmsgfku/";
}

Di chain lokal Hardhat, tokenURI(1) mengembalikan ipfs://bafybeifuwwkzdzittkxf5ghlmsq2k6jqasyheos6mb3vgz4l73qcmsgfku/1. Kenapa gak simpan JSON-nya langsung di contract? Menyimpan 393 byte itu di mapping(uint256 => string) menghabiskan 339.798 gas per token, karena tiap 32 byte storage disimpan oleh semua node. Dengan _baseURI, biaya tambahan per token nol, dan CID tetap menjamin isinya gak bisa diganti.

Mengganti isi berarti CID baru

Ubah "L" jadi "XL", CID kopi/1 berubah total, dan CID folder ikut berubah karena folder menyimpan CID anak-anaknya. _baseURI KaosEdisiKopi adalah teks tetap di bytecode, jadi tokenURI(1) tetap menunjuk ke folder lama dengan ukuran L. Itu jawaban tebakannya. Ini justru jaminannya: pembeli tahu metadata yang ia beli gak bisa diubah diam-diam. Kalau Raka ingin bisa mengubahnya, ia harus menulis fungsi setBaseURI (onlyOwner), dan jaminan itu hilang.

Pinning: tanpa pin, file bisa hilang

Node IPFS cuma wajib menyimpan file yang ia pin. Sisanya boleh dibuang oleh garbage collection. Raka mencoba di node lokalnya:

$ ipfs pin rm bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i
unpinned bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i
$ ipfs repo gc
removed bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i
...
$ ipfs cat --offline bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i
Error: block was not found locally (offline): ipld: could not find bafkreiccib257y3ea6vz6yjtteeiftjj6wzohtemafb5w5nccfb4f44n3i

Folder kopi masih ter-pin dan ipfs cat .../1 masih jalan, tapi gambarnya hilang. Pin folder cuma menahan file di dalam folder; gambar yang disebut lewat teks "image" gak ikut. Jadi pin gambar dan metadata, di lebih dari satu tempat: node sendiri dan layanan pinning.

Gateway dan ipfs://

Browser biasa belum bisa membuka ipfs://. Gateway menerjemahkannya ke HTTP: https://ipfs.io/ipfs/<CID>/1 atau https://<CID>.ipfs.dweb.link/1. Wallet dan marketplace melakukan itu otomatis. Yang ditulis di contract tetap ipfs://<CID>, bukan URL gateway, supaya NFT-nya gak terikat ke satu perusahaan. Gateway publik juga harus dipercaya; klien seperti @helia/verified-fetch mengecek hash sendiri.

Apa yang dijamin "desentralisasi"

Arweave adalah alternatif dengan model lain: jaringan blockchain sendiri tempat kamu membayar sekali di depan untuk penyimpanan jangka panjang, dibiayai dana abadi (endowment) jaringan. Datanya publik dan gak bisa dihapus, alamatnya ID transaksi (ar://...). Cocok untuk metadata yang memang harus permanen, tapi biayanya per byte di muka dan kamu bergantung pada ekonomi jaringan itu.

⚠️ Jebakan yang sering ketemu

TL;DR: IPFS adalah sistem file terdistribusi peer-to-peer dengan content addressing: CID = b + base32(versi 01, codec, multihash SHA-256 isi file). kubo 0.43.1 masih memberi CIDv0 (Qm...) kecuali --cid-version 1 (bafkrei... untuk file, bafybei... untuk folder). Metadata KOPI ada di folder kopi/ dengan CID bafybeifuwwk..., gambar di ipfs://bafkreiccib..., dan _baseURI mengembalikan ipfs://<CID folder>/, jadi tokenURI(1) = ipfs://.../1. Menyimpan JSON 393 byte di contract butuh 339.798 gas per token; IPFS murah dan CID menjamin isinya gak diganti, tapi cuma selama ada yang pin. Ubah isi berarti CID baru. Tulis ipfs:// di contract dan pakai gateway cuma untuk menampilkan. Arweave menukar biaya di muka dengan penyimpanan jangka panjang.

Yang akan kamu pelajari