共識演算法PoS及Go語言實現
相對於pow來說,pos共識演算法在計算方面有了很大的進步,因為不需要去進行像pow一樣的“難度解密”,取代他的而是對於股權的證明。在pos當中,塊是已經生成的,我們生成新的塊的過程是基於每個節點的“財產”的數量,如果一個驗證者他身上的資產越多,那麼他獲取下一個區塊的記賬權的可能性會越大。
實現Proof of Stake主要功能點
·我們將有一箇中心化的TCP伺服器節點,其他的節點可以連線到這個伺服器上
·最新的區塊鏈的狀態將定期的廣播到每個節點上
·每個節點都可以公平的提議建立新的區塊
·基於每個節點的“資產”的數量,選舉出一個獲勝者,並將獲勝者(區塊)新增到區塊鏈當中去
實現PoS
設定TCP伺服器的埠
新建 .env 檔案,新增 PORT=9000
安裝依賴軟體
$ go get github.com/davecgh/go-spew/spew
$ go get github.com/joho/godotenv
和之前的Pow演算法一樣,需要使用spew和godotenv來輔助實現
引入相應的包
新建main.go檔案
package main
import(
"bufio"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"math/rand"
"net"
"os"
"strconv"
"sync"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/joho/godotenv"
)
定義全域性變數
type Blockstruct{
Index int
Timestamp string
BPM int
PrevHash string
Hash string
Validator string//由原先的difficulty改為了現在validator
}
var Blockchain []Block
var tempBlocks []Block// tempBlocks 是臨時儲存單元,在區塊被選出來並新增到 BlockChain 之前,臨時儲存在這裡
var candidateBlocks = make(chan Block)//chan建立的是一個fifo佇列,fifo先進先出
//candidateBlocks 是 Block 的通道,任何一個節點在提出一個新塊時都將它傳送到這個通道
var announcements = make(chan string)// announcements 也是一個通道,我們的主Go TCP伺服器將向所有節點廣播最新的區塊鏈
var mutex = &sync.Mutex{}
var validators = make(map[string]int)//validators 是節點的儲存map,同時也會儲存每個節點持有的令牌數
// map初始化使用make函式
生成區塊函式
func generateBlock(oldBlock Block, BPM int, address string) (Block, error) {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index +1
newBlock.Timestamp = t.String()
newBlock.BPM = BPM
newBlock.PrevHash = oldBlock.Hash
newBlock.Hash = calculateBlockHash(newBlock)
newBlock.Validator = address
return newBlock, nil
}
func calculateHash(s string) string {
h := sha256.New()
h.Write([]byte(s))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
//calculateBlockHash 是對一個 block 進行 hash,將一個 block 的所有欄位連線到一起後,再呼叫 calculateHash 將字串轉為 SHA256 hash 。
func calculateBlockHash(block Block) string {
record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHash
return calculateHash(record)
}
驗證區塊內容
func isBlockValid(newBlock, oldBlock Block) bool {
if newBlock.Index != oldBlock.Index +1{
return false
}
if newBlock.PrevHash != oldBlock.Hash{
return false
}
if calculateBlockHash(newBlock) != oldBlock.Hash{
return false
}
return true
}
驗證者
func handleConn(conn net.Conn) {
defer conn.Close()//defer語句延遲執行一個函式,該函式被推遲到當包含它的程式返回時(包含它的函式 執行了return語句/執行到函式結尾自動返回/對應的goroutine panic)執行。
go func(){
for {
msg := <-announcements
io.WriteString(conn, msg)
}
}()
// 驗證者地址
var address string
// 驗證者輸入他所擁有的 tokens,tokens 的值越大,越容易獲得新區塊的記賬權
io.WriteString(conn,"Enter token balance:")
// 允許驗證者輸入他持有的令牌數量,然後,該驗證者被分配一個 SHA256地址,隨後該驗證者地址和驗證者的令牌數被新增到驗證者列表validators 中。
scanBalance := bufio.NewScanner(conn)
for scanBalance.Scan(){
balance, err := strconv.Atoi(scanBalance.Text())
if err != nil {
log.Printf("%v not a number: %v", scanBalance.Text(), err)
return
}
t := time.Now()
address = calculateHash(t.String())
validators[address] = balance
fmt.Println(validators)
break
}
io.WriteString(conn,"\nEnter a new BPM:")
scanBPM := bufio.NewScanner(conn)
go func(){
for {
for scanBPM.Scan() {
bpm, err := strconv.Atoi(scanBPM.Text())
if err != nil {
log.Printf("%v not a number: %v", scanBPM.Text(), err)
delete(validators, address)
conn.Close()
}
mutex.Lock()
oldLastIndex := Blockchain[len(Blockchain) -1]
mutex.Unlock()
newBlock, err := generateBlock(oldLastIndex, bpm, address)
if err != nil {
log.Println(err)
continue
}
if isBlockValid(newBlock, oldLastIndex) {
candidateBlocks <- newBlock
}
io.WriteString(conn,"\n Enter a new BPM:")
}
}
}()
for {
time.Sleep(time.Minute)
mutex.Lock()
output, err := json.Marshal(Blockchain)
mutex.Unlock()
if err != nil {
log.Fatal(err)
}
io.WriteString(conn, string(output) +"\n")
}
}
選擇獲取記賬權的節點
func pickWinner(){
time.Sleep(30 * time.Second)
mutex.Lock()
temp := tempBlocks
mutex.Unlock()
lotteryPool := []string{}
if len(temp) >0{
OUTER:
for _, block :=range temp {
for _, node :=range lotteryPool {
if block.Validator == node {
continue OUTER
}
}
mutex.Lock()
setValidators := validators
mutex.Unlock()
k, ok := setValidators[block.Validator]
if ok {
for i :=0; i < k; i++ {
lotteryPool = append(lotteryPool, block.Validator)
}
}
}
s := rand.NewSource(time.Now().Unix())
r := rand.New(s)
lotteryWinner := lotteryPool[r.Intn(len(lotteryPool))]
for _, block :=range temp {
if block.Validator == lotteryWinner{
mutex.Lock()
Blockchain = append(Blockchain, block)
mutex.Unlock()
for _=range validators {
announcements <-"\n winning validator: " + lotteryWinner +"\n"
}
break
}
}
}
mutex.Lock()
tempBlocks = []Block{}
mutex.Unlock()
}
主函式
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
// 建立初始區塊
t := time.Now()
genesisBlock := Block{}
genesisBlock = Block{0, t.String(),0, calculateBlockHash(genesisBlock),""," "}
spew.Dump(genesisBlock)
Blockchain = append(Blockchain, genesisBlock)
httpPort := os.Getenv("PORT")
server, err := net.Listen("tcp",":" + httpPort)
if err != nil {
log.Fatal(err)
}
log.Println("HTTP Server Listening on port :", httpPort)
defer server.Close()
go func() {
for candidate :=range candidateBlocks {
mutex.Lock()
tempBlocks = append(tempBlocks, candidate)
mutex.Unlock()
}
}()
go func() {
for {
pickWinner()
}
}()
for{
conn, err := server.Accept()
if err != nil {
log.Fatal(err)
}
go handleConn(conn)
}
}
以上就是全部的實現過程,僅供參考
相關文章
- (二)區塊鏈的共識演算法:PoS 及其 例子 程式碼 實現區塊鏈演算法
- 一文搞懂 ZigZag 演算法及 Go 語言的實現演算法Go
- Go語言————1、初識GO語言Go
- 共識演算法之爭(PBFT,Raft,PoW,PoS,DPoS,Ripple)演算法Raft
- Go語言實現RPCGoRPC
- 【go共識演算法】-POWGo演算法
- 以太坊的POS共識機制
- 區塊鏈共識演算法(3)PoS權益證明演算法區塊鏈演算法
- go語言實現掃雷Go
- 使用Go語言從零編寫PoS區塊鏈(譯)Go區塊鏈
- 初識go語言Go
- 使用 Go 語言實現簡單的文字識別(OCR)Go
- 01 . Go語言實現SSH遠端終端及WebSocketGoWeb
- Go 語言介面及使用介面實現連結串列插入Go
- go語言實現ssh打隧道Go
- Go語言interface底層實現Go
- go語言依賴注入實現Go依賴注入
- Go語言實現TCP通訊GoTCP
- GO語言 實現埠掃描Go
- 初識Go語言-1Go
- go語言實現自己的RPC:go rpc codecGoRPC
- Go語言map的底層實現Go
- Go語言實現的Java Stream APIGoJavaAPI
- Go語言實現HTTPS加密協議GoHTTP加密協議
- 檔案複製(Go語言實現)Go
- 線性迴歸 go 語言實現Go
- 排序演算法-C語言實現排序演算法C語言
- go 學習筆記之初識 go 語言Go筆記
- Go 語言實現解析器翻譯Go
- Go 語言實現 QQ 掃碼登陸Go
- Go語言實現位元組記錄鎖Go
- go語言使用切片實現線性表Go
- 通俗講解:PoW共識機制與以太坊的關係、Ghost協議 及 Casper PoS共識機制的變種協議
- PID演算法的C語言實現演算法C語言
- Go 語言實踐(一)Go
- Go 語言實戰 GraphQLGo
- go語言錯題及答案整理Go
- Go語言反射(reflect)及應用Go反射