פרק 4: בניית ליבת הבלוקצ'יין
מבוא
בפרק זה נלמד כיצד לבנות את ליבת הבלוקצ'יין שלך, כולל הגדרת בלוק הג'נסיס, קביעת פרמטרי הבלוקצ'יין, ויישום אלגוריתם הקונצנזוס Proof of Stake (PoS). נשתמש בשפת Go כדי לבנות את הבלוקצ'יין.
שלב 1: הגדרת הבלוקצ'יין שלך
הקמת בלוק הג'נסיס
בלוק הג'נסיס הוא הבלוק הראשון בשרשרת הבלוקים. הוא מכיל מידע ראשוני המגדיר את הבלוקצ'יין שלך.
-
צור קובץ בשם
genesis.json
בתיקיית הפרויקט שלך והוסף את התוכן הבא:
{
"config": {
"chainId": 1234,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"difficulty": "0x4000",
"gasLimit": "0x8000000",
"alloc": {}
}
השתמש ב-Go-Ethereum (Geth) כדי לאתחל את הבלוקצ'יין שלך עם בלוק הג'נסיס:
geth init path/to/genesis.json
הגדרת פרמטרי הבלוקצ'יין
פרמטרי הבלוקצ'יין כוללים את קושי הכרייה, זמן הבלוק, גודל הבלוק ועוד.
- נעדכן את קובץ
genesis.json
כך שיכיל את הפרמטרים המתאימים:
{
"config": {
"chainId": 1234,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0
},
"difficulty": "0x20000",
"gasLimit": "0x2fefd8",
"alloc": {
"0x0000000000000000000000000000000000000001": {
"balance": "0x1"
}
}
}
שלב 2: יישום אלגוריתם הקונצנזוס של PoS
סקירה של אלגוריתמי PoS (כמו Casper, Tendermint)
ישנם מספר אלגוריתמי PoS שניתן להשתמש בהם. אנו נבחר באלגוריתם פשוט ליישום במדריך זה.
יישום צעד-אחר-צעד של PoS
נבנה אלגוריתם PoS בסיסי ב-Go שמאפשר למשתמשים להפקיד מטבעות ולקבל תגמולים בהתאם.
-
צור פרויקט Go חדש:
mkdir my-pos-blockchain
cd my-pos-blockchain
go mod init my-pos-blockchain
צור קובץ main.go
עם התוכן הבא:
package main
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/crypto"
)
// Block represents each 'item' in the blockchain
type Block struct {
Timestamp int64
Data []byte
PrevBlockHash []byte
Hash []byte
Validator []byte
}
// Blockchain is a series of validated Blocks
type Blockchain struct {
blocks []*Block
}
var validators = make(map[string]int)
// NewBlock creates and returns Block
func NewBlock(data string, prevBlockHash []byte, validator []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}, validator}
block.Hash = block.calculateHash()
return block
}
// calculateHash calculates and returns Block's hash
func (b *Block) calculateHash() []byte {
record := string(b.Timestamp) + string(b.Data) + string(b.PrevBlockHash) + string(b.Validator)
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hashed
}
// AddBlock saves the block into the blockchain
func (bc *Blockchain) AddBlock(data string, validator []byte) {
prevBlock := bc.blocks[len(bc.blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash, validator)
if validateBlock(newBlock, prevBlock) {
bc.blocks = append(bc.blocks, newBlock)
validators[string(validator)] += 1
}
}
// validateBlock checks if block's hash is valid
func validateBlock(newBlock, prevBlock *Block) bool {
if string(newBlock.PrevBlockHash) != string(prevBlock.Hash) {
return false
}
if !isValidValidator(newBlock.Validator) {
return false
}
return true
}
// isValidValidator checks if the validator is authorized
func isValidValidator(validator []byte) bool {
_, ok := validators[string(validator)]
return ok
}
// NewBlockchain creates a new Blockchain with genesis Block
func NewBlockchain() *Blockchain {
return &Blockchain{[]*Block{NewBlock("Genesis Block", []byte{}, []byte("Genesis Validator"))}}
}
func main() {
// Create a new Blockchain instance
bc := NewBlockchain()
// Generate a new validator key
privateKey, err := crypto.GenerateKey()
if err != nil {
fmt.Println(err)
return
}
publicKey := privateKey.Public().(*ecdsa.PublicKey)
validator := crypto.FromECDSAPub(publicKey)
// Add validator to the list
validators[hex.EncodeToString(validator)] = 0
// Add a new block
bc.AddBlock("First Block Data", validator)
for _, block := range bc.blocks {
fmt.Printf("Prev. hash: %xn", block.PrevBlockHash)
fmt.Printf("Data: %sn", block.Data)
fmt.Printf("Hash: %xn", block.Hash)
fmt.Printf("Validator: %xnn", block.Validator)
}
}
הסבר מפורט על הקוד
-
מבנה הבלוק (Block)
- כל בלוק בשרשרת הבלוקים מיוצג על ידי מבנה (struct) המכיל את השדות הבאים:
Timestamp
: הזמן שבו נוצר הבלוק.Data
: הנתונים המאוחסנים בבלוק.PrevBlockHash
: ההאש של הבלוק הקודם בשרשרת.Hash
: ההאש של הבלוק הנוכחי.Validator
: הכתובת של המאמת (Validator) שיצר את הבלוק.
- כל בלוק בשרשרת הבלוקים מיוצג על ידי מבנה (struct) המכיל את השדות הבאים:
-
חישוב ההאש (calculateHash)
- הפונקציה
calculateHash
מחשבת ומחזירה את ההאש של הבלוק על בסיס השדות שלו.
- הפונקציה
-
הוספת בלוק לבלוקצ'יין (AddBlock)
- הפונקציה
AddBlock
מוסיפה בלוק חדש לבלוקצ'יין אם הוא תקין. - היא מוודאת שהבלוק הקודם תואם ושמאמת הבלוק מורשה.
- הפונקציה
-
אימות הבלוק (validateBlock)
- הפונקציה
validateBlock
בודקת אם ההאש של הבלוק החדש תואם להאש של הבלוק הקודם ואם המאמת מורשה.
- הפונקציה
-
אימות המאמת (isValidValidator)
- הפונקציה
isValidValidator
בודקת אם המאמת מורשה.
- הפונקציה
-
יצירת בלוקצ'יין חדש (NewBlockchain)
- הפונקציה
NewBlockchain
יוצרת בלוקצ'יין חדש עם בלוק ג'נסיס.
- הפונקציה
-
הפונקציה הראשית (main)
- הפונקציה
main
יוצרת בלוקצ'יין חדש, יוצרת מפתח מאמת חדש, מוסיפה אותו לרשימת המאמתים, ומוסיפה בלוק חדש לבלוקצ'יין.
- הפונקציה
שלב 3: בדיקות ואימות
בדיקת הבלוקצ'יין שלך
כדי לוודא שהבלוקצ'יין שלך פועל כראוי, הרץ את התוכנית ובדוק את הפלט.
-
הרץ את התוכנית:
go run main.go
בדוק את הפלט, הוא אמור להראות כך:
Prev. hash: 0000000000000000000000000000000000000000000000000000000000000000
Data: Genesis Block
Hash: 9b25cfb2e3c44ae9882c8b8d34edc0071d2ff77b6a62dfd9a0fa287c32abcc55
Validator: 47656e657369732056616c696461746f72
Prev. hash: 9b25cfb2e3c44ae9882c8b8d34edc0071d2ff77b6a62dfd9a0fa287c32abcc55
Data: First Block Data
Hash: 8f0f6a0b68a90a8edb34b7f4a9d6396e08cc57109eb7e2d482b104bfe84d8ef4
Validator: <מפתח המאמת שלך>
סיכום
בפרק זה למדנו כיצד לבנות את ליבת הבלוקצ'יין שלך, כולל הגדרת בלוק הג'נסיס, קביעת פרמטרי הבלוקצ'יין, ויישום אלגוריתם הקונצנזוס Proof of Stake (PoS). יצרנו בלוקצ'יין בסיסי בשפת Go, הוספנו בלוק חדש ואימתנו את המאמתים. השתמשנו באלגוריתם PoS בסיסי כדי להמחיש כיצד פועל הבלוקצ'יין שלך.
בפרקים הבאים נלמד כיצד לפתח חוזים חכמים, להקים נוד מלא, ולבנות חוקר בלוקים ועוד.