+1

Building Blockchain in Go. Part 1: Basic Prototype

Tại bài viết trước thì mình đã giới thiệu về cách build 1 Simple blockchain bằng Java, các nguyên lý cấu tạo, cũng như là cơ chế generate hash của 1 block. Trong quá trình tìm hiểu về blockchain mình có đọc được 1 seri về build blockchain trên GoLang, thì mình xin phép được translate this article đến cho các ae đã, đang và sẽ học ngôn ngữ này. Phần 1 của seri này sẽ đi build Basic Prototype

1. Setup Go Runtime

Windows:

Linux và Mac OS X

  • Chúng ta sẽ cài Go thông qua Homebrew, nếu bạn nào chưa cài Homebrew thì chạy câu lệnh bên dưới để install nó ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" Sau khi cài xong Homebrew, chúng ta cài Go với lệnh: $ brew install go --cross-compile-common

Mac OS X Installer

  • Nếu không thích cài bằng dòng lệnh thì các bạn có thể tải bộ cài từ trang chủ https://golang.org/dl/

2. Setting environment variables for Go

Windows

  • Trên Windows, chúng ta sẽ cài đặt biến môi trường bằng cách click phải vào My Computer chọn Properties, chọn tab Advanced và click nút Environment Variables.

  • Nếu bạn cài đặt Go vào thư mục mặc định là C:\Go thì bạn cần cấu hình như sau: ・Tạo một biến mới tên là GOROOT với giá trị là C:\Go ・Chọn biến PATH có sẵn, thêm vào sau dấu chấm phẩy ; cuối dòng đường dẫn sau: C:\Go\bin;

Linux và Mac OS X

Trên các máy Unix, bạn cài đặt biến môi trường bằng cách chỉnh sửa file $HOME/.profile hoặc $HOME/.bash_profile. Nếu không tìm thấy biến $HOME, có thể thay nó bằng /user/local Hãy thêm nội dung sau: export GOROOT=$HOME/go export PATH=$PATH:$GOROOT/bin

Run

Bây giờ chúng ta sẽ kiểm tra xem Go đã được cài hoàn chỉnh hay chưa, bật Terminal (hoặc Comman Line trên Windows) gõ: $ go version Nếu đã cài đặt xong thì output sẽ hiện ra như này: go version go1.9.3 windows/amd64

OK, giờ ta sẽ đi xây dựng blockchain trên Go nào! Let's Go!

3. Build Blockchain Structure

Block

Mình sẽ đi giải thích khái niệm Block nó là gì, nó có mỗi liên hệ như thế nào với Blockchain. Block nó là 1 khối lưu trữ thông tin dữ liệu, về cơ bản mỗi block sẽ bao gồm transactions, time, hash, previous hash. Vì vậy ta sẽ tạo định nghĩa cấu trúc của 1 block như sau:

type Block struct {
	Timestamp     int64
	Data          []byte
	PrevBlockHash []byte
	Hash          []byte
}
  • Timestamp : thời gian block đó được tạo ra
  • Data : thông tin dữ liệu thực có trong block đó
  • PrevBlockHash : lưu trữ hash của block trước nó
  • Hash: hash của block.

Vậy hash nó được tạo ra như nào? Rất đơn giản, ta chỉ việc lấy fields trong block ra, nối chúng lại với nhau, rồi tính toán 1 SHA-256 hash dựa trên cái chuỗi mà chúng ta vừa nối lại với nhau đó. Ta sẽ triển khai 1 hàm gọi là SetHash để calculate hash như sau:

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[:]
}

Tiếp đến implement hàm để tạo ra 1 block chứa các thông tin time, data, previous hash, hash:

func NewBlock(data string, prevBlockHash []byte) *Block {
	block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
	block.SetHash()
	return block
}

OK, done build a block. Giờ ta sẽ implement a blockchain.

Blockchain

type Blockchain struct {
	blocks []*Block
}

Blockchain có thể nói là 1 singly linked list mà mỗi block là một phần tử. Vì vậy ở trên ta đã implement blockchain với array.

Add blocks vào blockchain đã dựng:

func (bc *Blockchain) AddBlock(data string) {
	prevBlock := bc.blocks[len(bc.blocks)-1]
	newBlock := NewBlock(data, prevBlock.Hash)
	bc.blocks = append(bc.blocks, newBlock)
}

Để add block mới, chúng ta cần phải có 1 block đã tồn tại, nhưng vẫn chưa có block nào trong blockchain của chúng ta cả. Vì thế trong bất kỳ blockchain nào cần phải có ít nhất 1 block đã tồn tại, block đầu tiên trong chuỗi, và nó thường được gọi với cái tên Genesis Block, block của sự bắt đầu =)). Implement Genesis block như sau:

func NewGenesisBlock() *Block {
	return NewBlock("Genesis Block", []byte{})
}

Bây giờ ta cần phải implement hàm để tạo 1 blockchain với genesis block:

func NewBlockchain() *Blockchain {
	return &Blockchain{[]*Block{NewGenesisBlock()}}
}

Xong rồi đấy, giờ check xem blockchain của chúng ta tạo ra có hoạt động ko nào =))

func main() {
	bc := NewBlockchain()

	bc.AddBlock("Send 1 BTC to Ivan")
	bc.AddBlock("Send 2 more BTC to Ivan")

	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: 4bc4a2108484cdbe666bf1dc0ca7e489ac3091c56f9b1c3ceb9f9779802457e2

Prev. hash: 4bc4a2108484cdbe666bf1dc0ca7e489ac3091c56f9b1c3ceb9f9779802457e2
Data: Send 1 BTC to Ivan
Hash: d7f4f06a633577f3ad00840c2a937246376d8fe312790a89ccffb6e6424ebaf2

Prev. hash: d7f4f06a633577f3ad00840c2a937246376d8fe312790a89ccffb6e6424ebaf2
Data: Send 2 more BTC to Ivan
Hash: 7db814e9d6b4f7298e0aea15deb1148699969b30fc4e672440384908e7adcfda

4. Conclusion

Chúng ta vừa xây dựng 1 blockchain prototype hết sức đơn giản, nó chỉ là 1 mảng gồm các block, với mỗi block đều có 1 kết nối tới block trước nó. Trên thực tế thì blockchain nó còn phức tạp nhiều hơn nữa. Trong blockchain của chúng ta tạo ra thì việc thêm blocks rất dễ và nhanh chóng, nhưng trên 1 cái blockchain thực sự thì việc nhận được sự cho phép để thêm 1 block mới nó còn yêu cầu 1 số thứ nữa. Và 1 trong số đó chính là cơ chế Proof-of-Work. Bởi blockchain là 1 cơ sở dữ liệu phân tán và không có bất kỳ 1 ai trực tiếp quản lý nó cả. Vậy nên muốn thêm 1 block mới vào chuỗi thì cần phải nhận được sự chấp nhận của những ng tham gia vào mạng lưới đó (cơ chế đồng thuận). Trong bài viết tới mình sẽ giới thiệu cho các bạn về Proof-of-Work, cái cách Proof-of-Work làm việc.

5. Reference


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí