美文网首页
共识算法PoS及Go语言实现

共识算法PoS及Go语言实现

作者: 帅气的昵称都有人用了 | 来源:发表于2018-10-09 16:02 被阅读0次

相对于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及Go语言实现

      本文链接:https://www.haomeiwen.com/subject/fgfyaftx.html