All posts

Membuat Blockchain Dengan Golang

6 min read
Blockchain

Membuat Blockchain Dengan Golang

Jadi, apa itu blockchain? kita bisa mulai dengan membayangkan sebuah excel yang dibagikan kepada banyak orang. Setiap baris pada file excel tersebut berisi catatan transaksi yang pernah terjadi dan akan diperbaharui setiap kali ada transaksi baru. Itulah analogi termudah dari blockchain.

Blockchain merupakan database yang tidak hanya tersimpan pada satu tempat, melainkan menyebar di berbagai tempat, dan setiap individu yang terlibat di dalamnya memiliki salinan lengkap atau sebagian dari database tersebut. Oleh karena itu, tidak sembarang orang dapat menambahkan catatan baru ke dalam blockchain, sebab diperlukan persetujuan dari semua pengguna yang memiliki salinan data tersebut

Cara Kerja Blockchain

Kemudian, bagaimana blockchain bekerja? Kembali lagi ke analogi excel kita, ketika transaksi baru dilakukan, sebuah baris baru akan ditambahkan. Dalam blockchain, baris tersebut disebut block. Block merupakan tempat penyimpanan berbagai informasi. Misalnya, block pada Bitcoin bertujuan untuk menyimpan informasi transaksi, yang merupakan inti dari jaringan Bitcoin. Selain itu, sebuah block juga dapat berisi informasi teknis, seperti versi block tersebut, waktu pembuatan block, dan hash dari block sebelumnya.

Sebelum sebuah block dapat dimasukkan ke dalam blockchain, detail dari transaksi tersebut harus diperiksa dan disetujui terlebih dahulu oleh pengguna lainnya.

Setelah pengguna lain setuju bahwa transaksi tersebut valid, sebuah block baru dapat ditambahkan ke dalam blockchain. Yang membuat blockchain menjadi unik adalah bahwa setelah block ditambahkan ke blockchain, ia tidak bisa diubah atau dihapus. Ini memberikan transparansi dan keamanan yang luar biasa pada semua transaksi.

Mulai Membuat Blockchain

Setelah kita memahami tentang blockchain secara singkat, sekarang saatnya kita mencoba membuat versi sederhana dari blockchain

  1. Buatlah Folder baru dan berikan nama yang sesuai, misalnya **blockchain. **buatkan file main.go berserta fungsi main didalamnya
  2. Buat file bernama block.go lalu tulis kode di bawah untuk membuat struct block
    GO
    type Block struct {
     Timestamp     int64
     Data          []byte
     PrevBlockHash []byte
     Hash          []byte
    

}

CODE

Mari kita bahas apa saja yang ada di dalam struct `block`:
- **Timestamp** berfungsi sebagai penanda waktu kapan Block dibuat
- **Data** merupakan inti dari block. Dalam konteks kita yaitu bitcoin, data merujuk pada detail transaksi yang dilakukan
- **PrevBlockHash** menyimpan hash dari block yang ada sebelumnya.  Fitur ini memungkinkan blockchain menjadi seperti rantai, dimana setiap block akan saling berhubungan dengan block sebelumnya. Karena itulah di sebut blockchain (rantai block)
- **Hash **adalah kode unik dari setiap Block. Hash ini mengacak informasi yang ada di dalam blok menjadi deretan angka dan huruf acak. Setiap block memiliki hash yang berbeda
1. Selanjutnya, kita akan membuat fungsi yang digunakan untuk menghasilkan hash dari sebuah block 
```go
func (b *Block) SetHash() {
 timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))
 headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{})
 hash := sha256.Sum256(headers)

 b.Hash = hash[:]
}

Mari kita lihat apa saja yang ada di dalam fungsi SetHash

  • timestamp := []byte(strconv.FormatInt(b.Timestamp, 10)) Baris ini mengkonversi Timestamp dari block (yang merupakan tipe data int64) ke string, dan kemudian ke slice byte.
  • headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{}) Baris ini menggabungkan PrevBlockHashData, dan timestamp menjadi satu slice byte. bytes.Join menggabungkan elemen-elemen slice byte dan memisahkannya menggunakan pemisah yang diberikan, dalam hal ini pemisahnya adalah slice byte kosong.
  • hash := sha256.Sum256(headers) Baris ini menghitung hash SHA-256 dari headers.Sum256 adalah fungsi dari paket crypto/sha256 dan menghasilkan hash dalam bentuk array byte dengan ukuran 32.
  • Baris kode b.Hash = hash[:] menetapkan nilai hash yang baru dihitung ke dalam attribut Hash pada objek Blockhash[:] mengambil array byte dan membuat salinan dalam bentuk slice byte. Dalam konteks ini, b adalah pointer ke objek Block kita. Oleh karena itu, nilai hash yang dihasilkan akan disimpan pada pointer b.
  1. Setelah membuat fungsi SetHash, langkah berikutnya adalah membuat fungsi untuk menciptakan block baru. Dalam fungsi ini kita akan mengunakan fungsi SetHash yang telah dibuat sebelumnya untuk menghasilkan hash yang diinginkan.
    GO
    func NewBlock(data string, prevBlockHash []byte) *Block {
     block := &Block{Timestamp: 0, Data: []byte(data), PrevBlockHash: prevBlockHash, Hash: []byte{}}
     block.SetHash()
     return block
    

}

CODE

- `block := &Block{Timestamp: 0, Data: []byte(data), PrevBlockHash: prevBlockHash, Hash: []byte{}}` Baris ini membuat variabel baru dari struck `Block` dengan nilai: 
  - Timestamp diberikan 0
  - Data akan diisi detail transaksi
  - PrevBlockHash diisi dengan hash block sebelumnya 
  - Hash diinisialisasi sebagai slice byte kosong terlebih dahulu.
- `block.SetHash()`. Baris ini memanggil fungsi `SetHash` yang telah kita buat sebelumnya. Fungsi ini akan menghitung nilai hash berdasarkan `Timestamp`, `Data`, dan `PrevBlockHash`.
1. Setelah berhasil membuat beberapa fungsi yang berhubungan dengan block, langkah selanjutnya adalah membuat fungsi yang bertujuan untuk menambahkan block ke dalam rantai block yang sudah ada. Buatlah file bernama `blockchain.go` lalu buatlah struck bernama blockchain di dalamnya
```go
type Blockchain struct {
 blocks []*Block
}

Struct ini bertujuan untuk menambung beberapa block

  1. Lalu kita buatkan fungsi untuk menambahkan block kedalam Blockchain
    GO
    func (bc *Blockchain) AddBlock(data string) {
     prevBlock := bc.blocks[len(bc.blocks)-1]
     newBlock := NewBlock(data, prevBlock.Hash)
     bc.blocks = append(bc.blocks, newBlock)
    

}

CODE

Fungsi `AddBlock`  kita buat ini bertujuan untuk menambahkan block baru ke dalam blockchain.
- `prevBlock := bc.blocks[len(bc.blocks)-1]` Baris ini bertujuan untuk memperoleh block terakhir (terbaru) dalam blockchain saat ini. Kita bisa mendapatkan blok terakhir dengan mengakses elemen terakhir dalam slice `blocks` milik pointer `bc` .
- `newBlock := NewBlock(data, prevBlock.Hash)` Baris ini membuat blok baru dengan menggunakan fungsi `NewBlock` yang sudah kita buat pada file `block.go`. Fungsi ini mengambil data yang diberikan sebagai argumen dan hash dari `prevBlock` untuk membuat block baru.
- `bc.blocks = append(bc.blocks, newBlock)`Baris ini menambahkan blok baru yang dibuat pada baris sebelumnya ke dalam slice  `blocks` milik `bc`
1. Untuk menambahkan block baru, kita membutuhkan block sebelumnya yang sudah ada, tetapi tetapi bagaimana jika dalam blockchain kita belum ada block sama sekali. Oleh karena itu, dalam blockchain, harus ada setidaknya satu block pertama dalam rantai, block ini disebut genesis block
```go
func NewGenesisBlock() *Block {
 return NewBlock("Genesis Block", []byte{})
}

fungsi ini memangil fungsi NewBlock yang sebelumnya sudah kita buat, dengan memasukan Genesis Block untuk parameter data dan []byte{} untuk prevBlockHash

  1. Sekarang, kita dapat membuat fungsi yang bertujuan untuk menciptakan blockchain dan akan mengunakan fungsi NewGenesisBlock untuk membuat block pertama.
    GO
    func NewBlockchain() *Blockchain {
     return &Blockchain{[]*Block{NewGenesisBlock()}}
    

}

CODE

`return &Blockchain{[]*Block{NewGenesisBlock()}} `  baris ini bertujuan untuk mengembalikan sebuah pointer blockchain yang berisi array dari pointer block. Array ini hanya memiliki satu block di dalamnya sebagai block awal yang dihasilkan oleh fungsi `NewGenesisBlock()`
1. Setelah membuat semua fungsi yang dibutuhkan, kita bisa mulai memangilnya pada fungsi main di file `main.go`
```go
func main() {
 bc := NewBlockchain()

 bc.AddBlock("Kirim 1 BTC to Hajid")
 bc.AddBlock("Kirim 2 BTC Lagi to Budi")

 for _, block := range bc.blocks {
 	fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
 	fmt.Printf("Data: %s\n", block.Data)
 	fmt.Printf("Hash: %x\n", block.Hash)
 	fmt.Println()
 }
}

/*
Output :
Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168

Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Kirim 1 BTC to Hajid
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1

Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Kirim 2 BTC Lagi to Budi
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1
*/
  1. Sekarang kita sudah berhasil membuat versi sederhana dari blockchain, dengan menggunakan array block yang saling terhubung. pada kasus sebenarnya blockchain jauh lebih kompleks. terdapat banyak mekanisme yang harus di buat. Sebagai contoh, salah satu mekanisme penting dalam sistem Bitcoin adalah Proof-of-Work (PoW). PoW dirancang dengan tujuan yang sangat spesifik yaitu untuk mencegah potensi spam dan serangan DDoS kepada sistem. Mekanisme ini memastikan integritas dan keamanan di dalam jaringan blockchain.

Sumber utama tulisan ini berasal dari artikel https://jeiwan.net/posts/building-blockchain-in-go-part-1/. Untuk pemahaman yang lebih mendalam dan lengkap, saya sarankan Anda untuk mengikuti membaca tulisan tersebut

Tujuan dari penulisan ini adalah untuk mencatat proses pembelajaran saya saat mengikuti tutorial tersebut. Saya berpikir bahwa dengan menuangkan catatan saya dalam bentuk blog, maka akan membantu orang lain yang ingin mengikuti tutorial yang sama

Full source codes: https://github.com/hajidalakhtar/blockchain-sederhana