如何使用Go構建權益區塊鏈證明 | 區塊鏈研究實驗室
火幣網(huobi.com)最新可用網址(點擊下圖直達註冊!)
火必交易所,曾经的火币交易所!
欧易OKX三大交易所,稳定好用!
币安全球第一大交易所!安全!
隨著區塊鏈給世界市場帶來的革命,在作出預測之前瞭解基礎知識至關重要。在本文中,我們將探討權益證明的基礎知識,該證明是一種區塊鏈協議,類似於一種在區塊鏈中偽造新區塊的彩票方法。
瞭解權益證明
Go中的權益證明
導入“區塊鏈”
package main
import (
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"log"
math "math/rand"
"time"
)
type PoSNetwork struct {
Blockchain []*Block
BlockchainHead *Block
Validators []*Node
}
type Node struct {
Stake int
Address string
}
type Block struct {
Timestamp string
PrevHash string
Hash string
ValidatorAddr string
}
逐塊建造區塊鏈磚
func (n PoSNetwork) GenerateNewBlock(Validator *Node) ([]*Block, *Block, error) {
if err := n.ValidateBlockchain(); err != nil {
Validator.Stake -= 10
return n.Blockchain, n.BlockchainHead, err
}
currentTime := time.Now().String()
newBlock := &Block {
Timestamp: currentTime,
PrevHash: n.BlockchainHead.Hash,
Hash: NewBlockHash(n.BlockchainHead),
ValidatorAddr: Validator.Address,
}
if err := n.ValidateBlockCandidate(newBlock); err != nil {
Validator.Stake -= 10
return n.Blockchain, n.BlockchainHead, err
} else {
n.Blockchain = append(n.Blockchain, newBlock)
}
return n.Blockchain, newBlock, nil
}
func NewBlockHash(block *Block) string {
blockInfo := block.Timestamp + block.PrevHash + block.Hash + block.ValidatorAddr
return newHash(blockInfo)
}
func newHash(s string) string {
h := sha256.New()
h.Write([]byte(s))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
驗證我們的區塊鏈
func (n PoSNetwork) ValidateBlockchain() error {
if len(n.Blockchain) <= 1 {
return nil
}
currBlockIdx := len(n.Blockchain)-1
prevBlockIdx := len(n.Blockchain)-2
for prevBlockIdx >= 0 {
currBlock := n.Blockchain[currBlockIdx]
prevBlock := n.Blockchain[prevBlockIdx]
if currBlock.PrevHash != prevBlock.Hash {
return errors.New("blockchain has inconsistent hashes")
}
if currBlock.Timestamp <= prevBlock.Timestamp {
return errors.New("blockchain has inconsistent timestamps")
}
if NewBlockHash(prevBlock) != currBlock.Hash {
return errors.New("blockchain has inconsistent hash generation")
}
currBlockIdx--
prevBlockIdx--
}
return nil
}
func (n PoSNetwork) ValidateBlockCandidate(newBlock *Block) error {
if n.BlockchainHead.Hash != newBlock.PrevHash {
return errors.New("blockchain HEAD hash is not equal to new block previous hash")
}
if n.BlockchainHead.Timestamp >= newBlock.Timestamp {
return errors.New("blockchain HEAD timestamp is greater than or equal to new block timestamp")
}
if NewBlockHash(n.BlockchainHead) != newBlock.Hash {
return errors.New("new block hash of blockchain HEAD does not equal new block hash")
}
return nil
}
那麼,我們如何決定何時添加新塊?
func (n PoSNetwork) NewNode(stake int) []*Node {
newNode := &Node{
Stake: stake,
Address: randAddress(),
}
n.Validators = append(n.Validators, newNode)
return n.Validators
}
func randAddress() string {
b := make([]byte, 16)
_, _ = math.Read(b)
return fmt.Sprintf("%x", b)
}
func (n PoSNetwork) SelectWinner() (*Node, error) {
var winnerPool []*Node
totalStake := 0
for _, node := range n.Validators {
if node.Stake > 0 {
winnerPool = append(winnerPool, node)
totalStake += node.Stake
}
}
if winnerPool == nil {
return nil, errors.New("there are no nodes with stake in the network")
}
winnerNumber := math.Intn(totalStake)
tmp := 0
for _, node := range n.Validators {
tmp += node.Stake
if winnerNumber < tmp {
return node, nil
}
}
return nil, errors.New("a winner should have been picked but wasn't")
}
匯集全部
我們現在所需要的就是將我們的函數和數據類型綁定在一起。我們在main()函數中做好所有的事情,第一步是設置一個隨機種子與當前時間作為我們的輸入。不要使用時間作為隨機種子的輸入,因為它實際上會在解碼哈希輸出時引入安全漏洞。
在這個示例中,我們需要實例化一個新的ProofStake網絡,其中有一個被稱為Genesis塊,也就是我們所知的塊。區塊鏈中的第一個區塊。一旦我們這樣做,我們也設置網絡的BlockchainHead等於第一個塊。
func main() {
// set random seed
math.Seed(time.Now().UnixNano())
// generate an initial PoS network including a blockchain with a genesis block.
genesisTime := time.Now().String()
pos := &PoSNetwork{
Blockchain: []*Block{
{
Timestamp: genesisTime,
PrevHash: "",
Hash: newHash(genesisTime),
ValidatorAddr: "",
},
},
}
pos.BlockchainHead = pos.Blockchain[0]
// instantiate nodes to act as validators in our network
pos.Validators = pos.NewNode(60)
pos.Validators = pos.NewNode(40)
// build 5 additions to the blockchain
for i := 0; i < 5; i++ {
winner, err := pos.SelectWinner()
if err != nil {
log.Fatal(err)
}
winner.Stake += 10
pos.Blockchain, pos.BlockchainHead, err = pos.GenerateNewBlock(winner)
if err != nil {
log.Fatal(err)
}
fmt.Println("Round ", i)
fmt.Println("\tAddress:", pos.Validators[0].Address, "-Stake:", pos.Validators[0].Stake)
fmt.Println("\tAddress:", pos.Validators[1].Address, "-Stake:", pos.Validators[1].Stake)
}
pos.PrintBlockchainInfo()
}
然後,我們添加兩個節點的網絡作為驗證器與60和40令牌作為他們的初始股份。在五次迭代中,我們將為區塊鏈選擇一個新的贏傢,如果有任何錯誤,我們的程序將崩潰-因為做原型我們通過新選擇的贏傢產生一個新的塊,並打印出每一輪的每個節點的總樁。
最後,我們將打印出我們新制作的區塊鏈:
$ go run main.go
Round 0
Address: f8d44bb083078de97b8428f4f9548130 -Stake: 70
Address: de6ae18584f02b3388569191a04a4b4a -Stake: 40
Round 1
Address: f8d44bb083078de97b8428f4f9548130 -Stake: 70
Address: de6ae18584f02b3388569191a04a4b4a -Stake: 50
Round 2
Address: f8d44bb083078de97b8428f4f9548130 -Stake: 80
Address: de6ae18584f02b3388569191a04a4b4a -Stake: 50
Round 3
Address: f8d44bb083078de97b8428f4f9548130 -Stake: 90
Address: de6ae18584f02b3388569191a04a4b4a -Stake: 50
Round 4
Address: f8d44bb083078de97b8428f4f9548130 -Stake: 100
Address: de6ae18584f02b3388569191a04a4b4a -Stake: 50
Block 0 Info:
Timestamp: 2021-04-12 MDT m=+0.000120025
Previous Hash:
Hash: c5d04de14efed52ce84889c6382f9d307d5b98093d93a84b419478
Validator Address:
Block 1 Info:
Timestamp: 2021-04-12 MDT m=+0.000277288
Previous Hash: c5d04de14efed52ce84889c6382f9d307d5b98093d93a
Hash: d58e90a75b71ac62ef938fc0148314a7f864ad50bd702f959e2d27
Validator Address: f8d44bb083078de97b8428f4f9548130
Block 2 Info:
Timestamp: 2021-04-12 MDT m=+0.000306562
Previous Hash: d58e90a75b71ac62ef938fc0148314a7f864ad50bd702
Hash: e6bfdd6c2c869607e2d9a81b84ddf4478756fedff78a03746cde11
Validator Address: de6ae18584f02b3388569191a04a4b4a
Block 3 Info:
Timestamp: 2021-04-12 MDT m=+0.000321755
Previous Hash: e6bfdd6c2c869607e2d9a81b84ddf4478756fedff78a0
Hash: 8e3dbacc4a610b1665658bc9e7238963eda0d5bbbf3ce809e8fa6e
Validator Address: f8d44bb083078de97b8428f4f9548130
Block 4 Info:
Timestamp: 2021-04-12 MDT m=+0.000333024
Previous Hash: 8e3dbacc4a610b1665658bc9e7238963eda0d5bbbf3ce
Hash: 22760f8deb96c354a4050a3c48741be062bccfa9c51571c170065a
Validator Address: f8d44bb083078de97b8428f4f9548130
Block 5 Info:
Timestamp: 2021-04-12 MDT m=+0.000347521
Previous Hash: 22760f8deb96c354a4050a3c48741be062bccfa9c5157
Hash: d2a5047f7d8a7696c1d0fb9ec49b56d2e71bbcedaaebc83a18b7a5
Validator Address: f8d44bb083078de97b8428f4f9548130
作者:鏈三豐,來源:區塊鏈研究實驗室