Belajar Blockchain
Sumber: Build a Blockchain from Scratch in Go (2021) - By Lukas
Mengapa Memulai Pengembangan Blockchain?
Dua tahun lalu, saya berada di persimpangan jalan dalam karir saya. Saya sedang mencari pekerjaan pemrograman saya berikutnya setelah lima tahun berkecimpung dalam pengembangan di trivago.
Saya sedang memilih antara posisi di NewRelic atau posisi di sebuah startup baru. Yap. Saya memilih dan . Mengapa? Karena itu lebih baik untuk karir jangka panjang saya. Dan saya merekomendasikan Anda untuk melakukan hal yang sama.
Jika saya melanjutkan pengembangan , saya akan terus memprogram , sesekali mempelajari sesuatu yang baru. Sebagian besar waktu, saya akan memperbaiki , dan mungkin mengimplementasikan fitur bagus setiap dua sekali. Paling bagus, itu akan menjadi pilihan yang baik, aman, dan menarik, tetapi sedikit lambat untuk selera pribadi saya.
Paling buruk, saya akan mengerjakan yang rusak :) (Hanya bercanda, sangat bagus untuk melakukan pada bagian-bagian individual dari proyek dan membagi kepemilikan di antara tim-tim yang independen.)
Selain peluang yang menarik, ada juga aspek finansial dalam setiap pekerjaan. Kita semua punya tagihan yang harus dibayar. Di dunia , saya akan bersaing untuk kenaikan gaji dengan 10 juta lainnya, yang masing-masing memiliki pengalaman 20 tahun. Tentu saja bisa dilakukan, tetapi ini adalah perjuangan berat yang semakin sulit dari hari ke hari.
3.0 akan datang. Dalam sepuluh tahun terakhir, kita telah membantu membangun platform besar untuk komunikasi massa. Ingin update kehidupan? . Punya cerita? . Mau berbagi foto? . Sayangnya, platform-platform ini memiliki sisi gelap. Dan sisi gelap inilah yang menjadi kekuatan dari seluruh model bisnis mereka. Pengguna telah menyerahkan kedaulatan data mereka dan kehilangan perhatian karena iklan.
Tetapi tidak harus seperti ini.
Apakah Anda ingat ketika menjadi raja, dan semua orang punya blog? bertujuan untuk membangun kembali dan menyempurnakan visi ini. Bergabunglah dengan saya dan jelajahi ekonomi berbasis (tokenized economies
) baru yang mengoptimalkan pertukaran nilai antar partisipan dengan sepenuhnya menghilangkan perantara. Pelajari sifat kekal (immutability
), gabungkan dengan kriptografi asimetris (asymmetric cryptography
), dan kembangkan sistem baru yang transparan dan open-source
yang dapat dipercaya oleh pengguna sambil mencegah pembobolan data yang tersentralisasi.
Buku ini akan menunjukkan kepada Anda persis tentang hal itu.
Temui karakter utama buku ini. Andrej.
Andrej adalah pemilik bar di malam hari dan seorang pengembang perangkat lunak di siang hari di sebuah kota kecil Slovakia bernama Bardejov.
Andrej lelah dengan:
Memprogram aplikasi yang solid dan kuno.
Lupa berapa banyak uang yang dihutangi oleh teman dan kliennya untuk semua minuman vodka di malam Jumat yang belum dibayar.
Menghabiskan waktu mengumpulkan dan menghitung koin, mengembalikan uang kembalian, dan secara umum menyentuh uang kertas yang mungkin terkontaminasi COVID-19.
Memelihara berbagai kepingan plastik dan untuk sepak bola meja, , biliar, dan .
Andrej ingin sekali:
Memiliki riwayat aktivitas dan penjualan bar yang dapat diaudit dengan sempurna agar barnya sesuai dengan peraturan pajak.
Mengubah barnya menjadi lingkungan yang otonom, efisien dalam pembayaran, dan aman yang dapat dipercaya oleh pelanggannya.
"Ini akan menjadi mimpi dalam pemrograman!" katanya pada dirinya sendiri. "Saya akan menulis program sederhana dan menyimpan semua saldo klien saya dalam bentuk virtual."
"Setiap pelanggan baru akan memberi saya uang tunai, dan saya akan memberi mereka kredit digital saya dalam jumlah yang setara. tersebut akan mewakili unit moneter di dalam dan di luar bar."
"Para pengguna akan menggunakan tersebut untuk semua fungsionalitas bar, mulai dari membayar minuman, meminjamkan dan meminjamnya kepada teman-teman mereka, hingga bermain tenis meja, , dan (sepak bola meja)."
"Saya akan menamainya: The Blockchain Bar, !"
Memulai
Buku ini ditulis dalam bahasa , tetapi jangan khawatir - Anda tidak perlu memiliki pengalaman sebelumnya untuk mulai membaca buku ini. Ini adalah bahasa yang sangat kuat dan ramah bagi pemula, dan Anda akan cepat menguasainya.
Persyaratan
Saya merekomendasikan Anda memiliki pengalaman pemrograman 2+ tahun di / / , atau bahasa lain yang mirip dengan .
Mengapa Go?
Karena seperti , ini adalah teknologi yang fantastis untuk karir pemrograman Anda secara keseluruhan. adalah bahasa yang sedang tren dan dibayar lebih baik daripada posisi pada umumnya.
dioptimalkan untuk arsitektur . Anda dapat menjalankan (spawn
) ribuan ringan () tanpa masalah. Ini sangat praktis untuk perangkat lunak yang sangat paralel dan konkuren seperti jaringan . Dengan menulis perangkat lunak Anda dalam , Anda mencapai performa yang mendekati level secara langsung tanpa harus bersusah payah karena lupa membebaskan memori (free-up memory
).
juga mengkompilasi menjadi , yang membuatnya sangat portabel.
Tentu, ini adalah kelanjutan terjemahannya.
Pengguna 1, Andrej
Senin, 18 Maret.
Andrej mengenerate 1 juta .
Di dunia , adalah unit di dalam . Nilai riilnya dalam dolar atau euro berfluktuasi berdasarkan permintaan dan popularitasnya.
Setiap memiliki sebuah file “Genesis”. File Genesis digunakan untuk mendistribusikan pertama kepada para partisipan awal .
Semuanya dimulai dengan file yang sederhana sebagai contoh.
Andrej membuat file ./database/genesis.json
di mana ia mendefinisikan bahwa The Blockchain Bar akan memiliki 1 juta dan semuanya akan menjadi milik Andrej:
{
"genesis_time": "2019-03-18T00:00:00.000000000Z",
"chain_id": "the-blockchain-bar-ledger",
"balances": {
"andrej": 1000000
}
}
tersebut harus memiliki “utilitas” nyata, yaitu, sebuah kasus penggunaan (use case). Pengguna harus bisa membayar dengan tersebut sejak hari pertama! Andrej harus mematuhi regulator hukum (seperti SEC di Amerika Serikat). Adalah ilegal untuk menerbitkan sekuritas (security) yang tidak terdaftar. Di sisi lain, diperbolehkan, jadi ia segera mencetak dan menempelkan poster daftar harga baru di pintu barnya.
Andrej menetapkan nilai moneter awal untuk -nya agar ia bisa menukarkannya dengan euro, dolar, atau mata uang lainnya.
1 TBB token = 1€
Vodka shot
1 TBB
Orange juice
5 TBB
Burger
2 TBB
Crystal Head Vodka Bottle
950 TBB
Andrej juga memutuskan, ia harus mendapatkan 100 per hari karena telah memelihara dan memiliki ide disruptif yang cemerlang.
01 | Fakta Menarik Database MVP
Genesis () pertama di dibuat dan didistribusikan kepada investor awal dan dengan cara yang sama seperti milik Andrej.
Pada tahun 2017, selama ledakan (initial coin offerings) di jaringan , para pendiri proyek menulis dan mempresentasikan kepada investor. Sebuah adalah dokumen teknis yang menguraikan masalah kompleks dan solusi yang memungkinkan, dimaksudkan untuk mengedukasi dan menjelaskan suatu hal tertentu. Di dunia , berfungsi untuk menguraikan spesifikasi tentang bagaimana tersebut akan terlihat dan berperilaku setelah dikembangkan.
Proyek-proyek berhasil mengumpulkan antara €10 juta hingga €300 juta per ide .
Sebagai ganti uang (pendanaan ), nama-nama investor akan dimasukkan ke dalam “saldo genesis” awal, mirip seperti yang dilakukan Andrej. Harapan investor melalui adalah nilai koin genesis akan naik dan tim pengembang akan mewujudkan yang telah diuraikan.
Tentu saja, tidak semua ide membuahkan hasil. Investasi besar yang hilang karena ide-ide yang tidak jelas atau tidak lengkap adalah alasan mengapa menerima liputan negatif di media selama masa tersebut, dan mengapa beberapa orang masih menganggapnya sebagai hype. Tetapi teknologi yang mendasarinya sangat fantastis dan berguna, seperti yang akan Anda pelajari lebih lanjut di buku ini. Hanya saja teknologi ini telah disalahgunakan oleh beberapa oknum yang tidak bertanggung jawab.
01 | Ringkasan Database MVP
adalah sebuah .
Jumlah pasokan , saldo awal pengguna, dan pengaturan global Anda definisikan dalam sebuah file Genesis.
Tentu, ini lanjutannya.
02 | Mengubah State DB Global
Pesta yang Sepi
Senin, 25 Maret.
Setelah seminggu bekerja, fasilitas bar siap untuk menerima . Sayangnya, tidak ada yang datang, jadi Andrej memesan tiga sloki vodka untuk dirinya sendiri dan menulis perubahan di secarik kertas:
andrej-3; // 3 shots of vodka
andrej+3; // technically purchasing from his own bar
andrej+700; // Reward for a week of work (7x100 per day)
Untuk menghindari penghitungan ulang terbaru dari saldo setiap pelanggan, Andrej membuat file ./database/state.json
yang menyimpan saldo dalam format yang teragregasi.
DB yang baru:json
{
"balances": {
"andrej": 1000700
}
}
Bonus untuk BabaYaga
Selasa, 26 Maret.
Untuk mendatangkan pengunjung ke barnya, Andrej mengumumkan bonus eksklusif 100% bagi siapa saja yang membeli TBB dalam 24 jam ke depan.
Ting! Dia mendapatkan pelanggan pertamanya yang bernama BabaYaga. BabaYaga membeli senilai 1000€, dan untuk merayakannya, dia langsung membelanjakan 1 TBB untuk satu sloki vodka. Dia punya masalah kecanduan alkohol.
Transaksi DB yang ditulis di secarik kertas:
andrej-2000; // transfer ke BabaYaga (2 kali lipat, 2 * 1000, krna bonus 100%)
babayaga+2000; // pembelian di muka dengan bonus 100%
babayaga-1; // membayar 1 TBB untuk vodka
andrej+1; // pendapatan bar dari penjualan
andrej+100; // hadiah harian
DB yang baru:
JSON
{
"balances": {
"andrej": 998801,
"babayaga": 1999
}
}
Fakta Menarik
Proyek (initial coin offerings berbasis ) sering kali mendistribusikan genesis dengan bonus yang berbeda, tergantung pada berapa banyak yang Anda beli dan seberapa awal Anda melakukannya. Tim pengembang menawarkan, rata-rata, bonus 10-40% kepada “partisipan” awal.
Kata “investor” dihindari agar regulator hukum tidak menganggap tersebut sebagai sekuritas (security). Proyek-proyek tersebut akan berargumen bahwa produk utama mereka, yaitu , berfungsi seperti “poin loyalitas”.
Para “partisipan” ini kemudian bahkan menghasilkan keuntungan 1000% (empat angka nol!) dari investasi mereka dengan menjualnya ke publik melalui bursa (exchange) beberapa bulan kemudian.
Ringkasan
adalah sebuah . Jumlah pasokan , saldo awal pengguna, dan pengaturan global Anda definisikan dalam sebuah file Genesis. Saldo Genesis menunjukkan asli dari dan tidak akan pernah diperbarui setelahnya.
Perubahan pada disebut Transaksi ( atau ).
Tentu, ini adalah terjemahan dari bagian selanjutnya.
03 | Event Monolitik vs Transaksi
Para pengembang yang terbiasa dengan arsitektur event-sourcing pasti langsung mengenali prinsip-prinsip yang familiar di balik transaksi. Mereka benar. Transaksi merepresentasikan serangkaian event, dan adalah state akhir yang teragregasi dan terkalkulasi setelah memutar ulang (replaying) semua transaksi dalam urutan tertentu.
Andrej Mulai Pemrograman
Selasa malam, 26 Maret.
Ini adalah Selasa malam yang santai bagi Andrej. Merayakan klien pertamanya, ia memutuskan untuk bermain Starcraft⁸ dan membersihkan mesin pengembangan lokalnya dengan menghapus beberapa foto lama. Sayangnya, ia terlalu cepat menekan enter saat mengetik path perintah penghapusan di terminal sudo rm -rf /
. Ups.
Semua filenya, termasuk genesis.json
dan state.json
milik bar, hilang.
Andrej, sebagai seorang pengembang senior, berulang kali meneriakkan beberapa kata-kata kotor dengan sangat keras selama beberapa detik, tetapi dia tidak panik! Meskipun dia tidak punya cadangan (backup), dia punya sesuatu yang lebih baik — secarik kertas berisi semua transaksi . Satu-satunya hal yang perlu dia lakukan adalah memutar ulang semua transaksi satu per satu, dan state -nya akan pulih kembali.
Terkesan dengan keunggulan arsitektur berbasis event, ia memutuskan untuk memperluas solusi MVP-nya. Setiap aktivitas bar, seperti pembelian minuman individual, HARUS dicatat di dalam .
⁸https://www.youtube.com/watch?v=Ff4VIghrTMg&feature=youtu.be&t=51603
Setiap pelanggan akan direpresentasikan dalam DB menggunakan sebuah Account Struct
:
type Account string
Setiap Transaction
(TX - perubahan ) akan memiliki empat atribut berikut: from
, to
, value
, dan data
.
Atribut data
dengan satu nilai yang mungkin (reward
) mencatat bonus Andrej karena telah menciptakan dan secara artifisial meningkatkan total pasokan awal TBB (inflasi).
type Tx struct {
From Account `json:"from"`
To Account `json:"to"`
Value uint `json:"value"`
Data string `json:"data"`
}
func (t Tx) IsReward() bool {
return t.Data == "reward"
}
DB Genesis akan tetap berupa file JSON:
{
"genesis_time": "2019-03-18T00:00:00.000000000Z",
"chain_id": "the-blockchain-bar-ledger",
"balances": {
"andrej": 1000000
}
}
Semua transaksi, yang sebelumnya ditulis di secarik kertas, akan disimpan dalam file-teks lokal bernama tx.db
, diserialisasi dalam format JSON dan dipisahkan oleh karakter pemisah baris (line-break
):
{"from":"andrej","to":"andrej","value":3,"data":""}
{"from":"andrej","to":"andrej","value":700,"data":"reward"}
{"from":"andrej","to":"babayaga","value":2000,"data":""}
{"from":"andrej","to":"andrej","value":100,"data":"reward"}
{"from":"babayaga","to":"andrej","value":1,"data":""}
Komponen paling krusial yang merangkum semua logika bisnis adalah State
:
type State struct {
Balances map[Account]uint
txMempool []Tx
dbFile *os.File
}
Struct State
akan mengetahui semua saldo pengguna dan siapa yang mentransfer TBB kepada siapa, dan berapa banyak yang ditransfer.
State
ini dibangun dengan membaca saldo awal pengguna dari file genesis.json
:
func NewStateFromDisk() (*State, error) {
// dapatkan direktori kerja saat ini
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
genFilePath := filepath.Join(cwd, "database", "genesis.json")
gen, err := loadGenesis(genFilePath)
if err != nil {
return nil, err
}
balances := make(map[Account]uint)
for account, balance := range gen.Balances {
balances[account] = balance
}
Setelah itu, saldo State
dari genesis diperbarui dengan memutar ulang secara berurutan semua event dari tx.db
:
txDbFilePath := filepath.Join(cwd, "database", "tx.db")
f, err := os.OpenFile(txDbFilePath, os.O_APPEND|os.O_RDWR, 0600)
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(f)
state := &State{balances, make([]Tx, 0), f}
// Iterasi melalui setiap baris file tx.db
for scanner.Scan() {
if err := scanner.Err(); err != nil {
return nil, err
}
// Ubah TX yang di-encode JSON menjadi sebuah objek (struct)
var tx Tx
json.Unmarshal(scanner.Bytes(), &tx)
// Bangun kembali state (saldo pengguna),
// sebagai serangkaian event
if err := state.apply(tx); err != nil {
return nil, err
}
}
return state, nil
}
Komponen State
bertanggung jawab untuk:
Menambahkan transaksi baru ke
Mempool
Memvalidasi transaksi terhadap
State
saat ini (saldo pengirim mencukupi)Mengubah
state
Menyimpan (
persisting
) transaksi ke diskMenghitung saldo akun dengan memutar ulang semua transaksi sejak Genesis secara berurutan
Menambahkan transaksi baru ke Mempool
:
func (s *State) Add(tx Tx) error {
if err := s.apply(tx); err != nil {
return err
}
s.txMempool = append(s.txMempool, tx)
return nil
}
Menyimpan (persisting
) transaksi ke disk:
func (s *State) Persist() error {
// Buat salinan dari mempool karena s.txMempool akan dimodifikasi
// di dalam loop di bawah ini
mempool := make([]Tx, len(s.txMempool))
copy(mempool, s.txMempool)
for i := 0; i < len(mempool); i++ {
txJson, err := json.Marshal(mempool[i])
if err != nil {
return err
}
if _, err = s.dbFile.Write(append(txJson, '\n')); err != nil {
return err
}
// Hapus TX yang telah ditulis ke file dari mempool
s.txMempool = s.txMempool[1:]
}
return nil
}
Mengubah dan Memvalidasi state
:
func (s *State) apply(tx Tx) error {
if tx.IsReward() {
s.Balances[tx.To] += tx.Value
return nil
}
if tx.Value > s.Balances[tx.From] {
return fmt.Errorf("insufficient balance")
}
s.Balances[tx.From] -= tx.Value
s.Balances[tx.To] += tx.Value
return nil
}
Tentu, ini adalah kelanjutan dari terjemahan buku tersebut.
Membangun Command-Line-Interface (CLI)
Selasa malam, 26 Maret.
Andrej ingin cara yang mudah untuk menambahkan transaksi baru ke DB-nya dan melihat daftar saldo terbaru pelanggannya. Karena program dikompilasi menjadi , ia membangun sebuah CLI untuk programnya.
Cara termudah untuk mengembangkan program berbasis CLI di adalah dengan menggunakan pustaka pihak ketiga github.com/spf13/cobra
.
Andrej menginisialisasi manajer dependensi bawaan untuk proyeknya, yang disebut :
go mod init github.com/web3coach/the-blockchain-bar
Perintah akan secara otomatis mengambil pustaka apa pun yang Anda referensikan di dalam file Anda.
Andrej membuat direktori baru bernama cmd
dengan subdirektori tbb
:
mkdir -p ./cmd/tbb
Di dalamnya ia membuat file main.go
, yang berfungsi sebagai titik masuk (entry point) CLI program:
package main
import (
"os"
"github.com/spf13/cobra"
"fmt"
)
func main() {
var tbbCmd = &cobra.Command{
Use: "tbb",
Short: "The Blockchain Bar CLI",
Run: func(cmd *cobra.Command, args []string) {
},
}
err := tbbCmd.Execute()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Program dikompilasi menggunakan perintah install
:
$ go install ./cmd/tbb/...
go: finding github.com/spf13/cobra v1.0.0
go: downloading github.com/spf13/cobra v1.0.0
go: extracting github.com/spf13/cobra v1.0.0
akan mendeteksi pustaka yang hilang dan mengambilnya secara otomatis sebelum mengkompilasi program. Bergantung pada $GOPATH
Anda, program yang dihasilkan akan disimpan di folder $GOPATH/bin
.
$ echo $GOPATH
> /home/web3coach/go
$ which tbb
> /home/web3coach/go/bin/tbb
Anda sekarang dapat menjalankan tbb
dari terminal Anda, tetapi itu tidak akan melakukan apa-apa karena fungsi Run
di dalam file main.go
masih kosong.
Hal pertama yang dibutuhkan Andrej adalah dukungan versioning untuk program CLI tbb
-nya.
Di sebelah file main.go
, ia membuat perintah version.go
:
package main
import (
"fmt"
"github.com/spf13/cobra"
)
const Major = "0"
const Minor = "1"
const Fix = "0"
const Verbal = "TX Add && Balances List"
var versionCmd = &cobra.Command{
Use: "version",
Short: "Describes version.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Version: %s.%s.%s-beta %s", Major, Minor, Fix, Verbal)
},
}
Dia mengkompilasi dan menjalankannya:
$ go install ./cmd/tbb/...
$ tbb version
> Version: 0.1.0-beta TX Add && Balances List
Sempurna.
Sama seperti file version.go
, ia membuat file balances.go
:
func balancesCmd() *cobra.Command {
var balancesCmd = &cobra.Command{
Use: "balances",
Short: "Interact with balances (list...).",
PreRunE: func(cmd *cobra.Command, args []string) error {
return incorrectUsageErr()
},
Run: func(cmd *cobra.Command, args []string) {
},
}
balancesCmd.AddCommand(balancesListCmd)
return balancesCmd
}
Perintah balances
akan bertanggung jawab untuk memuat State
DB terbaru dan mencetaknya ke standard output:
var balancesListCmd = &cobra.Command{
Use: "list",
Short: "Lists all balances.",
Run: func(cmd *cobra.Command, args []string) {
state, err := database.NewStateFromDisk()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer state.Close()
fmt.Println("Saldo Akun:")
fmt.Println("__________________")
fmt.Println("")
for account, balance := range state.Balances {
fmt.Println(fmt.Sprintf("%s: %d", account, balance))
}
},
}
Andrej memverifikasi apakah perintah tersebut berfungsi seperti yang diharapkan. Seharusnya perintah ini mencetak saldo yang sama persis seperti yang didefinisikan dalam file Genesis karena file tx.db
masih kosong.
$ go install ./cmd/tbb/...
$ tbb balances list
Saldo Akun:
__________________
andrej: 1000000
Berhasil! Sekarang dia hanya butuh sebuah perintah untuk mencatat aktivitas bar.
Andrej membuat perintah ./cmd/tbb/tx.go
:
func txCmd() *cobra.Command {
var txsCmd = &cobra.Command{
Use: "tx",
Short: "Interact with txs (add...).",
PreRunE: func(cmd *cobra.Command, args []string) error {
return incorrectUsageErr()
},
Run: func(cmd *cobra.Command, args []string) {
},
}
txsCmd.AddCommand(txAddCmd())
return txsCmd
}
Perintah tbb tx add
menggunakan fungsi State.Add(tx)
untuk menyimpan event bar ke dalam sistem file:
func txAddCmd() *cobra.Command {
var cmd = &cobra.Command{
Use: "add",
Short: "Adds new TX to database.",
Run: func(cmd *cobra.Command, args []string) {
from, _ := cmd.Flags().GetString(flagFrom)
to, _ := cmd.Flags().GetString(flagTo)
value, _ := cmd.Flags().GetUint(flagValue)
fromAcc := database.NewAccount(from)
toAcc := database.NewAccount(to)
tx := database.NewTx(fromAcc, toAcc, value, "")
state, err := database.NewStateFromDisk()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// `defer` berarti, di akhir eksekusi fungsi ini,
// jalankan statement berikut (tutup file DB dengan semua TX)
defer state.Close()
// Tambahkan TX ke array dalam memori (pool)
err = state.Add(tx)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// Salin (flush) TX dari mempool ke disk
err = state.Persist()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println("TX successfully added to the ledger.")
},
}
Perintah tbb tx add
memiliki 3 flags wajib: --from
, --to
, dan --value
.
cmd.Flags().String(flagFrom, "", "Dari akun mana token akan dikirim")
cmd.MarkFlagRequired(flagFrom)
cmd.Flags().String(flagTo, "", "Ke akun mana token akan dikirim")
cmd.MarkFlagRequired(flagTo)
cmd.Flags().Uint(flagValue, 0, "Berapa banyak token yang akan dikirim")
cmd.MarkFlagRequired(flagValue)
return cmd
}
CLI-nya sudah selesai!
Andrej memindahkan semua transaksi dari kertas ke DB barunya:
$ tbb tx add --from=andrej --to=andrej --value=3
$ tbb tx add --from=andrej --to=andrej --value=700 --data=reward
$ tbb tx add --from=andrej --to=babayaga --value=2000
$ tbb tx add --from=andrej --to=andrej --value=100 --data=reward
$ tbb tx add --from=babayaga --to=andrej --value=1
Baca semua TX dari disk dan hitung state terbaru:
$ tbb balances list
Saldo Akun:
__________________
andrej: 998801
babayaga: 1999
Data bar berhasil dipulihkan! Fiuh, malam yang luar biasa!
Tentang Pustaka Cobra CLI
Hal yang baik tentang pustaka Cobra untuk pemrograman CLI adalah fitur-fitur tambahan yang disediakannya. Misalnya, Anda sekarang dapat menjalankan tbb help
dan itu akan mencetak semua sub-perintah TBB yang terdaftar beserta instruksi cara menggunakannya.
$ tbb help
The Blockchain Bar CLI
Usage:
tbb [flags]
tbb [command]
Available Commands:
balances Interact with balances (list...).
help Help about any command
tx Interact with txs (add...).
version Describes version.
Flags:
-h, --help help for tbb
Use "tbb [command] --help" for more information about a command.
Fakta Menarik
Secara tidak sengaja kehilangan data pelanggan adalah hal yang biasa terjadi di dunia korporat saat ini. memperbaiki ini dengan mendesentralisasi penyimpanan data.
Trik yang Andrej tanamkan ke dalam program dengan melewatkan verifikasi saldo untuk TX yang ditandai sebagai
reward
. dan bekerja dengan cara yang sama. Saldo dari Akun yang menambang (mined) sebuah block meningkat begitu saja sebagai subjek dari inflasi total pasokan yang mempengaruhi seluruh chain. Total pasokan dibatasi pada 21 juta BTC. Anda akan belajar lebih banyak tentang “mining” dan “blocks” di bab 7 dan 10.Komponen
State
danMempool
tidak unik untuk program ini. Andrej memilih nama dan desain agar sesuai dengan modelgo-Ethereum
yang disederhanakan, sehingga Anda dapat melihat sekilas ke dalam kode sumber inti .
Ringkasan
adalah sebuah . Jumlah pasokan , saldo awal pengguna, dan pengaturan global didefinisikan dalam sebuah file Genesis. Saldo Genesis menunjukkan apa state asli dari dan tidak akan pernah diperbarui setelahnya.
Perubahan pada state disebut Transaksi (). Transaksi pada dasarnya adalah Event kuno yang merepresentasikan tindakan di dalam sistem.
04 | Manusia Itu Serakah
Keserakahan Bisnis yang Tipikal
Rabu, 27 Maret.
BabaYaga berinvestasi sedikit terlalu banyak. Dia lupa bahwa pembayaran sewa flatnya sudah dekat, dan dia tidak punya uang. BabaYaga menelepon pemilik flatnya, Caesar.
BabaYaga: Hei Caesar, maaf, tapi aku tidak punya uang tunai untuk membayar sewa bulan ini…
Caesar: Kenapa tidak?
BabaYaga: The Blockchain Bar menawarkan bonus besar, dan aku membeli senilai 2000€ hanya dengan 1000€. Itu penawaran yang sangat bagus!
Caesar: Apa-apaan yang kamu bicarakan? Apa itu ? Apa pula itu ? Bisakah kamu membayarku dengan cara lain?
BabaYaga: Oh, jangan lagi. Aku bisa memberimu 1000 TBB senilai 1000€, dan kamu bisa menggunakannya di bar untuk membayar minumanmu! Biar aku telepon pemilik bar, Andrej, untuk melakukan transfer!
Caesar: Baiklah… Aku terima.
Andrej melakukan transfer, tetapi memutuskan untuk memotong biaya tambahan sebesar 50 TBB untuk jerih payahnya. Dia tidak mau, TAPI para pemegang saham bar yang berinvestasi padanya beberapa tahun lalu memaksanya untuk menghasilkan keuntungan sesegera mungkin.
BabaYaga kemungkinan besar tidak akan menyadari biaya yang relatif kecil ini, pikir Andrej dalam hati. Pada akhirnya, hanya dia yang punya akses ke DB.
Bash
// pembayaran sewa
$ tbb tx add --from=babayaga --to=caesar --value=1000
// pemotongan biaya tersembunyi
$ tbb tx add --from=babayaga --to=andrej --value=50
// hadiah baru untuk satu hari lagi memelihara DB
$ tbb tx add --from=andrej --to=andrej --value=100 --data=reward
Fakta Menarik 1/2
Kasus penggunaan nomor satu untuk adalah perbankan. Banyak proyek bertujuan untuk mengoptimalkan pertukaran uang domestik dan internasional di berbagai koridor mata uang (contohnya ).
Proyek lain fokus pada kebebasan dan identitas kedaulatan diri (Self-Sovereign Identity atau ) - sebuah gerakan digital yang mengakui bahwa seorang individu harus memiliki dan mengendalikan identitas dan uang mereka sendiri tanpa campur tangan otoritas administratif atau perantara terpusat lainnya. memungkinkan orang untuk berinteraksi di dunia digital dengan kebebasan dan kapasitas kepercayaan yang sama seperti yang mereka lakukan di dunia luring. (Contohnya / ).
Berikut adalah beberapa fakta menarik mengapa sangat cocok untuk menggantikan infrastruktur perbankan Anda saat ini.
Hal yang baik tentang virtual adalah fungibilitasnya - yaitu, kemampuannya untuk diperdagangkan, dengan setiap unitnya sama bergunanya dengan unit berikutnya. Melakukan transfer dari satu akun ke akun lain dapat dilakukan hanya dengan mengubah state . Cryptocurrency dapat diperdagangkan 24/7.
Anda tidak bisa memperdagangkan saham secara langsung. Anda perlu melalui seorang broker yang mengambil sebagian persentase dari total transaksi sebagai biaya (1-3% dari keuntungan tahunan rata-rata 7%).
Transfer bank internasional memakan waktu antara 3-10 hari kerja dan bisa memakan biaya hingga 5% dari nilai yang ditransfer! Jika Anda mengirim $10.000, Anda mungkin harus membayar hingga $500.¹¹
Teknologi di balik ini selama 40 tahun terakhir? File + .
¹¹https://www.ofx.com/en-au/faqs/how-much-does-it-cost-to-send-money-internationally/
Fakta Menarik 2/2
Apakah Anda pikir pasar saham itu adil? Bank, indeks, dan saham sangat terpusat dan dikendalikan oleh pemerintah dan kelompok swasta Wall Street. Pasar bebas? Wall Street mengontrol seberapa banyak harga bisa naik/turun dalam satu hari.
Sebagai contoh, Wall Street menghentikan perdagangan "Indeks S&P 500" setelah penurunan 7% untuk melindungi investor dan hedge funds mereka dari kerugian akibat orang-orang yang menjual saham mereka selama bulan Maret 2020 setelah berita COVID. Setelah itu, The FED (Bank Sentral AS) mencetak triliunan dolar untuk diri mereka sendiri guna menopang harga saham. Jika Anda seorang pengembang yang suka menabung dan menghindari utang, nilai tabungan Anda baru saja hilang dalam semalam dengan persentase yang tidak diketahui.
Banyak negara menuju imbal hasil negatif (negative yields), sebuah wilayah yang belum pernah dijelajahi dengan konsekuensi yang tidak diketahui. Apa artinya ini? Sebentar lagi Anda harus membayar bank untuk menyimpan tabungan Anda.
Inilah inflasi yang sesungguhnya. Anda dipaksa untuk membelanjakan uang Anda untuk mendukung sistem yang tidak Anda kontrol.
Ringkasan
Perangkat lunak tertutup dengan akses terpusat ke data dan aturan pribadi hanya menempatkan segelintir orang pada posisi berkuasa. Pengguna tidak punya pilihan, dan pemegang saham menjalankan bisnis untuk menghasilkan uang.
adalah sebuah . Jumlah pasokan , saldo awal pengguna, dan pengaturan global Anda definisikan dalam sebuah file Genesis. Saldo Genesis menunjukkan apa state asli dari dan tidak akan pernah diperbarui setelahnya.
Perubahan pada state disebut Transaksi (). Transaksi pada dasarnya adalah Event kuno yang merepresentasikan tindakan di dalam sistem.
Tentu, ini adalah terjemahan bagian selanjutnya.
05 | Mengapa Kita Membutuhkan Blockchain
BabaYaga Mencari Keadilan
Kamis, 28 Maret.
BabaYaga masuk ke bar untuk merayakan hari ulang tahunnya.
BabaYaga: Hei, Andrej! Hari ini ulang tahunku! Berikan aku botolmu yang paling mahal!
Andrej: Selamat ulang tahun! Ini dia: Crystal Head Vodka. Tapi kamu perlu membeli satu TBB tambahan. Harga botolnya 950 , dan saldomu 949.
BabaYaga: Apa?! Seharusnya saldoku 999 TBB!
Andrej: Transfer dana ke Caesar yang kamu minta minggu lalu memotong biaya 50 .
BabaYaga: Ini tidak bisa diterima! Aku tidak akan pernah setuju dengan biaya setinggi itu! Kamu tidak bisa melakukan ini, Andrej! Aku percaya pada sistemmu, tapi kamu sama tidak bisa diandalkannya dengan pemilik bisnis lainnya. Sesuatu harus berubah!
Andrej: Baiklah, begini. Kamu adalah pelanggan setiaku, dan aku tidak ingin membebankan biaya padamu, tapi para pemegang saham memaksaku. Biar aku program ulang sistemku dan membuatnya sepenuhnya transparan dan terdesentralisasi. Lagi pula, jika semua orang bisa berinteraksi dengan bar tanpa harus melaluiku, itu akan meningkatkan efisiensi bar secara signifikan dan menyeimbangkan tingkat kepercayaan!
Memesan minuman akan memakan waktu beberapa detik, bukan menit.
Pelanggan yang lupa dompetnya di rumah bisa meminjam atau meminjamkan satu sama lain.
Aku tidak perlu khawatir kehilangan data klien (lagi) karena semua orang akan memiliki salinannya.
-nya akan immutable (kekal/tidak bisa diubah), jadi begitu semua orang menyetujui state tertentu, tidak ada orang lain yang bisa mengubahnya atau memodifikasi riwayatnya dengan niat jahat. Sifat immutable ini juga akan membantu audit pajak tahunan!
Jika pemegang saham ingin memperkenalkan biaya baru atau menaikkan yang sudah ada, semua orang yang terlibat dalam sistem akan mengetahuinya dan harus menyetujuinya. Para pengguna dan pemilik bisnis bahkan mungkin harus terlibat bersama dalam suatu sistem tata kelola terdesentralisasi (decentralized governance), mungkin berdasarkan pemungutan suara. Jika terjadi ketidaksepakatan, para pengguna bisa pergi dengan membawa semua data mereka!
BabaYaga: Yah, kedengarannya bagus, tapi apa itu mungkin?
Andrej: Ya, kurasa begitu. Dengan sedikit hashing, linked lists, struktur data immutable, replikasi terdistribusi (distributed replication), dan kriptografi asimetris (asymmetric cryptography)!
BabaYaga: Aku sama sekali tidak mengerti apa yang baru saja kamu katakan, tapi lakukan saja hal geeky-mu itu, Andrej!
Satu hari lagi sistem berjalan, berarti 100 TBB lagi untuk Andrej karena memelihara dan meningkatkan :
Bash
$ tbb tx add --from=andrej --to=andrej --value=100 --data=reward
Fakta Menarik
Miners (penambang) dan juga menerima hadiah setiap ~15 menit karena menjalankan server (nodes) dan memvalidasi transaksi.
Setiap 15 menit, satu miner menerima 12.5 BTC (senilai $100.000 saat halaman ini ditulis) untuk menutupi biaya servernya + mendapatkan keuntungan.
Jaringan mengonsumsi listrik sebanyak seluruh negara Austria. Ini menyumbang 0,29% dari konsumsi listrik tahunan dunia.
Setiap tahunnya, jaringan ini mengonsumsi 76.84 TWh, menghasilkan jejak karbon 36.50 Mt CO2 (setara dengan Selandia Baru). Sumber.¹³
Mengapa? Anda akan belajar lebih banyak di Bab 11, di mana Anda akan memprogram algoritma mining dari awal!
PS: Algoritma kita akan mengonsumsi listrik sedikit lebih sedikit :)
Ringkasan
Perangkat lunak tertutup dengan akses terpusat ke data pribadi hanya menempatkan segelintir orang pada posisi berkuasa. Pengguna tidak punya pilihan, dan pemegang saham menjalankan bisnis untuk menghasilkan uang.
Pengembang bertujuan untuk mengembangkan protokol di mana pengusaha aplikasi dan pengguna bersinergi dalam hubungan yang transparan dan dapat diaudit. Spesifikasi sistem harus didefinisikan dengan baik sejak awal dan hanya berubah jika penggunanya mendukung perubahan tersebut.
adalah sebuah . Jumlah pasokan , saldo awal pengguna, dan pengaturan global didefinisikan dalam sebuah file Genesis. Saldo Genesis menunjukkan apa state asli dari dan tidak akan pernah diperbarui setelahnya.
Perubahan pada state disebut Transaksi (). Transaksi pada dasarnya adalah Event kuno yang merepresentasikan tindakan di dalam sistem.
06 | L’Hash de Immutable
Tingkat kesulitan teknis dimulai dari bagian ini! Konsepnya akan semakin menantang, tetapi pada saat yang sama, sangat menarik. Kencangkan sabuk pengaman Anda :)
Bagaimana Cara Memprogram Database yang Immutable?
Jumat, 29 Maret.
Jika Andrej ingin mencari tahu cara memprogram DB yang immutable (kekal/tidak dapat diubah), ia harus menyadari mengapa sistem database lain secara desain bersifat mutable (dapat diubah).
Ia memutuskan untuk menganalisis sebuah Tabel DB MySQL:
1
Andrej
998951
2
BabaYaga
949
3
Caesar
1000
Di DB MySQL, siapa pun yang memiliki akses dan alasan yang cukup baik dapat melakukan pembaruan tabel seperti:
UPDATE user_balance SET balance = balance + 100 WHERE id > 1
Memperbarui nilai di berbagai baris dimungkinkan karena baris-baris tabel tersebut bersifat independen, mutable, dan state terbarunya tidak terlihat jelas. Apa perubahan DB terbaru? Kolom terakhir diubah? Baris terakhir disisipkan? Jika demikian, bagaimana Andrej bisa tahu baris mana yang baru saja dihapus?
Jika baris dan state tabel saling terikat erat, dependen, a.k.a, memperbarui baris 1 akan menghasilkan tabel baru yang sama sekali berbeda, maka Andrej akan mencapai tujuannya, yaitu immutability.
Bagaimana cara mengetahui jika ada satu byte pun di dalam database yang telah berubah?
Immutabilitas melalui Fungsi Hash
Sabtu, 30 Maret.
Hashing adalah proses mengambil masukan string dengan panjang sembarang dan menghasilkan string hash dengan panjang tetap. Perubahan apa pun pada masukan akan menghasilkan hash baru yang berbeda.
package main
import (
"crypto/sha256"
"fmt"
)
func main() {
balancesHash := sha256.Sum256([]byte("| 1 | Andrej | 99895 |"))
fmt.Printf("%x\n", balancesHash)
// Keluaran: 6a04bd8e2...f70a3902374f21e089ae7cc3b200751
// Ubah saldo dari 99895 -> 99896
balancesHashDiff := sha256.Sum256([]byte("| 1 | Andrej | 99896 |"))
fmt.Printf("%x\n", balancesHashDiff)
// Keluaran: d04279207...ec6d280f6c7b3e2285758030292d5e1
}
Andrej juga memerlukan tingkat keamanan tertentu untuk database-nya, jadi ia memutuskan untuk menggunakan Fungsi Hash Kriptografi dengan properti sebagai berikut:
Bersifat deterministik;¹⁶ - pesan yang sama akan selalu menghasilkan hash yang sama.
Cepat untuk menghitung nilai hash untuk pesan apa pun.
Tidak mungkin (
infeasible
) untuk menghasilkan pesan dari nilai hash-nya kecuali dengan mencoba semua kemungkinan pesan.Perubahan kecil pada pesan akan mengubah nilai hash secara ekstensif sehingga nilai hash yang baru tampak tidak berkorelasi dengan nilai hash yang lama.
Tidak mungkin (
infeasible
)¹⁷ untuk menemukan dua pesan berbeda dengan nilai hash yang sama.
Mengimplementasikan Hashing Konten DB
Sabtu Malam, 30 Maret.
Andrej memodifikasi fungsi Persist()
untuk mengembalikan hash konten baru, yang disebut Snapshot
, setiap kali transaksi baru disimpan.
type Snapshot [32]byte
Snapshot
ini dihasilkan oleh fungsi hashing aman sha256
yang baru ini:
func (s *State) doSnapshot() error {
// Baca ulang seluruh file dari byte pertama
_, err := s.dbFile.Seek(0, 0)
if err != nil {
return err
}
txsData, err := ioutil.ReadAll(s.dbFile)
if err != nil {
return err
}
s.snapshot = sha256.Sum256(txsData)
return nil
}
Fungsi doSnapshot()
dipanggil oleh fungsi Persist()
yang telah dimodifikasi. Ketika sebuah transaksi baru ditulis ke dalam file tx.db
, Persist()
melakukan hash pada seluruh konten file dan mengembalikan "sidik jari" 32 byte-nya, yaitu hash.
(Diagram yang menggambarkan alur: Persist()
-> Menulis TX ke tx.db
-> Melakukan hash pada seluruh file tx.db
-> Menghasilkan hash)
Mulai saat ini, semua orang dapat dengan 100% percaya diri dan aman merujuk pada state database tertentu (kumpulan data) dengan hash snapshot yang spesifik.
Waktunya Latihan.
1/4 Jalankan perintah tbb balances list
dan periksa apakah saldonya cocok.
$ tbb balances list
Saldo akun pada 7d4a360f465d...
andrej: 999251
babayaga: 949
caesar: 1000
2/4 Hapus 2 baris terakhir dari ./database/tx.db
dan periksa kembali saldonya.
$ tbb balances list
Saldo akun pada 841770dcd3...
andrej: 999051
babayaga: 949
caesar: 1000
3/4 Beri hadiah pada Andrej untuk 2 hari terakhir (dari 28 hingga 30 Maret):
Transaksi Hadiah 1:
$ tbb tx add --from=andrej --to=andrej --value=100 --data=reward
Menyimpan TX baru ke disk:
{"from":"andrej","to":"andrej","value":100,"data":"reward"}
Snapshot DB Baru: ff2470c7043f5a34169b5dd38921ba6825b03b3facb83e426...
TX berhasil disimpan ke dalam ledger.
Transaksi Hadiah 2:
$ tbb tx add --from=andrej --to=andrej --value=100 --data=reward
Menyimpan TX baru ke disk:
{"from":"andrej","to":"andrej","value":100,"data":"reward"}
Snapshot DB Baru: 7d4a360f468b837b662816bcdc52c1869f99327d53ab4a9ca...
TX berhasil disimpan ke dalam ledger.
4/4 Jalankan perintah tbb balances list
dan pastikan saldo serta hash snapshot-nya sama seperti di awal.
$ tbb balances list
Saldo akun pada 7d4a360f465d...
andrej: 999251
babayaga: 949
caesar: 1000
Selesai!
Karena fungsi hash kriptografi sha256
, dengan masukan yang sama (file tx.db
saat ini dan 2x perintah tbb tx add
), menghasilkan keluaran yang sama, jika Anda mengikuti langkah-langkah yang persis sama di komputer Anda, Anda akan menghasilkan state database dan hash yang sama persis!
Ringkasan
Perangkat lunak tertutup dengan akses terpusat ke data pribadi hanya menempatkan segelintir orang pada posisi berkuasa. Pengguna tidak punya pilihan, dan pemegang saham menjalankan bisnis untuk menghasilkan uang.
Pengembang bertujuan untuk mengembangkan protokol di mana pengusaha aplikasi dan pengguna bersinergi dalam hubungan yang transparan dan dapat diaudit. Spesifikasi sistem harus didefinisikan dengan baik sejak awal dan hanya berubah jika penggunanya mendukung perubahan tersebut.
adalah database yang immutable. Pasokan , saldo awal pengguna, dan pengaturan global didefinisikan dalam sebuah file Genesis. Saldo Genesis menunjukkan apa state asli dari dan tidak akan pernah diperbarui setelahnya.
Perubahan pada state disebut Transaksi (). Transaksi pada dasarnya adalah Event kuno yang merepresentasikan tindakan di dalam sistem.
Konten database di-hash oleh fungsi hash kriptografi yang aman. Para partisipan menggunakan hash yang dihasilkan untuk merujuk pada state database tertentu.
07 | Model Pemrograman Blockchain
Meningkatkan Performa DB yang Immutable
Minggu, 31 Maret.
Andrej tidak hanya membangun database yang immutable, tetapi juga yang terdistribusi! Dia akan mendistribusikan dan mereplikasi semua data ke setiap komputer klien/pemangku kepentingan yang berinteraksi dengan bar untuk menghindari sentralisasi data dan satu sumber kebenaran yang mudah diserang. Ini merupakan tantangan performa.
Program TBB saat ini bekerja dengan baik dengan ukuran database kecil saat berjalan di satu komputer, tetapi ia memiliki dua kendala performa (bottleneck):
Mendistribusikan transaksi ke komputer lain satu per satu akan menjadi tidak efisien karena latensi jaringan dalam sistem terdistribusi.
Membuat hash snapshot dari database dan memvalidasinya memerlukan pembacaan dan hashing ulang seluruh DB—yang berpotensi berukuran beberapa gigabyte—dari awal untuk SETIAP TX BARU.
Untungnya, Andrej dapat menyelesaikan kedua masalah ini dengan mengimplementasikan Hashed Linked List yang dikombinasikan dengan Batch Strategy standar.
Batching adalah strategi umum saat bekerja dengan sistem database SQL/NoSQL/Lainnya. Strategi batch terdiri dari "menangani beberapa item sekaligus". Solusinya adalah dengan merangkum transaksi ke dalam "potongan-potongan" atau "block" yang saling terhubung.
Batch + Hash + Linked List ⇒ Blocks
Senin, 1 April.
Andrej tidak sedang bercanda (lihat tanggalnya). Dia merancang struktur data berikut untuk merangkum transaksi ke dalam batch:
type Hash [32]byte
type Block struct {
Header BlockHeader
TXs []Tx // hanya transaksi baru (payload)
}
type BlockHeader struct {
Parent Hash // referensi block induk
Time uint64
}
Dan dia mengganti nama struct Snapshot
menjadi Hash
.
Struct Block
akan memiliki 2 atribut, Header
dan Payload:
Payload menyimpan transaksi BARU.
Header menyimpan metadata block (REFERENSI HASH BLOCK INDUK, waktu).
Hashing lama yang lambat pada seluruh DB setelah setiap TX baru:
func (s *State) doSnapshot() error {
// Baca ulang seluruh file dari byte pertama
_, err := s.dbFile.Seek(0, 0)
if err != nil {
return err
}
txsData, err := ioutil.ReadAll(s.dbFile)
if err != nil {
return err
}
// Beri saya hash dari seluruh konten DB
s.snapshot = sha256.Sum256(txsData)
return nil
}
Hashing baru yang dioptimalkan - di mana Hash
32-byte dihitung dengan hanya melakukan hash pada Block terbaru yang di-encode sebagai JSON:
type Block struct {
Header BlockHeader // metadata (hash block induk + waktu)
TXs []Tx // hanya transaksi baru (payload)
}
func (b Block) Hash() (Hash, error) {
blockJson, err := json.Marshal(b)
if err != nil {
return Hash{}, err
}
return sha256.Sum256(blockJson), nil
}
Implementasi di atas dapat direpresentasikan secara visual sebagai model pemrograman blockchain:
block saling terhubung melalui atribut ParentHash
Mengapa referensi hash dari block induk diperlukan?
ParentHash
digunakan sebagai "checkpoint" yang andal, merepresentasikan dan merujuk pada konten database yang telah di-hash sebelumnya.
ParentHash
meningkatkan performa. Hanya data baru + referensi ke state sebelumnya yang perlu di-hash untuk mencapai immutability.
Contohnya, jika Anda mencoba mengubah nilai TX di Block 0
, itu akan menghasilkan hash Block 0
yang baru dan unik. Hash dari Block 1
, yang didasarkan pada referensi Block 0
sebagai induknya, oleh karena itu akan segera berubah juga. Efek berantai ini akan mempengaruhi semua block, membuat database penyerang berniat jahat menjadi tidak valid - berbeda dari para pemangku kepentingan database lainnya yang jujur.
Oleh karena itu, database penyerang akan dikecualikan dari partisipasi dalam jaringan. Mengapa? Anda akan mengetahuinya di Bab 10 - di mana Anda akan memprogram algoritma sinkronisasi peer-to-peer.
Cara Kerja Penambahan TX ke dalam Block
Senin Malam, 1 April.
Sebuah struct Tx
baru dibuat dari parameter cmd
:
// ... di dalam txAddCmd()
tx := database.NewTx(
database.NewAccount(from),
database.NewAccount(to),
value,
data,
)
Tx
tersebut kemudian disimpan di dalam mempool
milik State
(bisa satu atau beberapa Tx
):
state, err := database.NewStateFromDisk()
// ...
state.AddTx(tx)
Terakhir, fungsi state.Persist()
dieksekusi untuk menyalin transaksi dari mempool
ke dalam file database ./database/block.db
:
state.Persist()
Secara internal, fungsi Persist()
akan membuat Block
baru, meng-encode-nya menjadi JSON, dan menuliskannya ke DB.
func (s *State) Persist() (Hash, error) {
// Buat Block baru HANYA dengan TX yang baru
block := NewBlock(
s.latestBlockHash,
uint64(time.Now().Unix()),
s.txMempool,
)
blockHash, err := block.Hash()
if err != nil {
return Hash{}, err
}
blockFs := BlockFS{blockHash, block}
// Encode menjadi string JSON
blockFsJson, err := json.Marshal(blockFs)
if err != nil {
return Hash{}, err
}
fmt.Printf("Menyimpan Block baru ke disk:\n")
fmt.Printf("\t%s\n", blockFsJson)
// Tulis ke file DB di baris baru
err = s.dbFile.Write(append(blockFsJson, '\n'))
if err != nil {
return Hash{}, err
}
s.latestBlockHash = blockHash
// Reset mempool
s.txMempool = []Tx{}
return s.latestBlockHash, nil
}
Migrasi dari TX.db ke BLOCKS.db
Senin Malam, 1 April.
Saat ini, semua transaksi ditulis di file ./database/tx.db
. Untuk memindahkannya ke dalam block, Andrej mengembangkan sebuah perintah bantuan sederhana.
Dia menempatkan perintah tersebut di file ./cmd/tbbmigrate/main.go
:
func main() {
state, err := database.NewStateFromDisk()
// ...
defer state.Close()
Dia merangkum 2 TX pertama bar ke dalam Block 0
dan menyimpannya ke disk:
block0 := database.NewBlock(
database.Hash{},
uint64(time.Now().Unix()),
[]database.Tx{
database.NewTx("andrej", "andrej", 3, ""),
database.NewTx("andrej", "andrej", 700, "reward"),
},
)
state.AddBlock(block0)
block0hash, _ := state.Persist()
// Hash Block 0: 07536e2c559b0a4566b84802...
// Hash Induk Block 0: 0000000...
Hasil yang ditulis ke disk:
{
"hash": "07536e2c55ffa629a105f61c8f6c5f1c7289d139e02639436...",
"block": {
"header": {
"parent": "0000000000000000000000000000000000000000000000000...",
"time": 1556563065
},
"payload": [
{"from":"andrej","to":"andrej","value":3,"data":""},
{"from":"andrej","to":"andrej","value":700,"data":"reward"}
]
}
}
Hash induknya kosong karena ini adalah Block
pertama yang pernah dibuat. Andrej memasukkan sisa riwayat TX ke dalam Block 1
. Block 1
merujuk pada Block 0
sebagai induknya hanya dengan menggunakan hash dari Block 0
. Tidak perlu melakukan hash ulang pada seluruh konten Block 0
! Jauh lebih sedikit siklus CPU yang terbuang, dengan tingkat keamanan dan immutability yang sama tercapai.
block1 := database.NewBlock(
block0hash,
uint64(time.Now().Unix()),
[]database.Tx{
// ... daftar 6 transaksi lainnya
},
)
state.AddBlock(block1)
state.Persist()
// Hash Block 1: 2efe28463821660834cf8e3cc555...
// Hash Induk Block 1: 07536e2c559b0a4566b84802...
Eksperimen dengan Perintah Migrasi
Waktunya Latihan.
1/3 Hapus 2 block yang ada dari ./database/block.db
yang telah di-commit oleh Andrej di branch saat ini.
cat /dev/null > ./database/block.db
2/3 Kompilasi kode dan jalankan perintah migrasi yang baru.
go install ./cmd/...
tbbmigrate
3/3 Amati 2 block baru yang di-encode dalam JSON ditulis ke dalam ./database/block.db
seperti yang diprogram di ./cmd/tbbmigrate/main.go
. Anda akan melihat keluaran yang mirip dengan ini di terminal Anda:
Menyimpan Block baru ke disk:
{"hash":"8a05167d2f...","block":{"header":{...},"payload":[{...},{...}]}}
Menyimpan Block baru ke disk:
{"hash":"c70775ae5e...","block":{"header":{"parent":"8a05167d2f..."},"payload":[{...},{...}, ...]}}
PS: Hash block Anda akan berbeda karena atribut block.time
diatur saat runtime - yaitu saat Anda menjalankan perintah tbbmigrate
.
Ringkasan
Transaksi dikelompokkan ke dalam batch untuk alasan performa. Sekumpulan transaksi membentuk sebuah Block. Setiap block di-encode dan di-hash menggunakan fungsi hash kriptografi yang aman.
Block berisi Header
dan Payload
. Header
menyimpan berbagai metadata seperti waktu dan referensi ke Parent Block
(state database immutable sebelumnya). Payload
membawa transaksi database yang baru.
TO BE CONTINUE...
Last updated