共识算法4--股权权益证明算法改进
共识算法2--股权权益证明简介及算法实现 对PoS算法进行了简介,并初步实现了一个简单版本的PoS算法,本文根据共识算法2对PoS算法进一步完善,实现从电脑终端加入用户,然后根据用户持币时间采用PoS确定挖矿用户。
1、股权权益证明改进说明
博文共识算法2中采用初始化用户的方式来生成挖矿用户,并根据其币龄采用PoS算法挖矿,但是实际中不可能采用初始化用户的方法生成用户,多为动态添加用户。因此,此处对其进行改进,通过系统终端添加挖矿用户,并根据其币龄采用PoS挖矿。
2、PoS算法改进实现
本文改进的PoS算法具体实施如下:
PoS服务启动,等待终端用户加入(若无用户则采用默认的noMiner来挖矿),用户加入后将其放进对应的节点数组中, 系统每10s中通过PoS选择一个矿工挖矿,并将挖到的矿放到区块数组中。
本案例不足之处:暂未对用户添加奖励,挖矿后年未同步更新各个用户的币龄,未对终端用户做区分,后续将逐渐完善这些不足之处。
PoS算法单机版本源码:
// c6_PoS
package main
//该版本PoS实现在终端中加入挖矿用户,挖矿时候根据挖矿用户的持币时间和随机函数来确定哪个用户挖矿
import (
"bufio"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"math/rand"
"net"
"os"
"strconv"
"time"
)
//创建区块
type Block struct {
Index int //区块高度
Data int //交易记录、数据
Prehash string
Hash string
Timestamp string
Validator string //终端地址
}
//计算string 的 hash值
func calculateHash(record string) string {
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
//计算Block 的 hash值
func calculateBlockHash(block Block) string {
record := block.Timestamp + strconv.Itoa(block.Data) + block.Prehash + strconv.Itoa(block.Index)
hashCode := calculateHash(record)
return hashCode
}
//生成区块切片,用于存放区块链
var Blockchain []Block
//生成一个新的区块
func generateNextBlock(oldBlock Block, data int, vald string) Block {
var newBlock Block
//设置区块高度
newBlock.Index = oldBlock.Index + 1
newBlock.Timestamp = time.Now().String()
newBlock.Prehash = oldBlock.Hash
newBlock.Data = data
newBlock.Hash = calculateBlockHash(newBlock)
newBlock.Validator = vald
//添加到区块链
Blockchain = append(Blockchain, newBlock)
return newBlock
}
//创建创世区块
func genesisBlock() Block {
var genesisBlock = Block{0, 0, "00prehash", "00hash", time.Now().String(), "00"}
//计算创世块的hash
genesisBlock.Hash = calculateBlockHash(genesisBlock)
Blockchain = append(Blockchain, genesisBlock)
return genesisBlock
}
//创建conn终端连接的数组,用于保存终端用户
var connAddr []net.Conn
//创建节点类型
type Node struct {
//终端地址
Addres string
//持币时间
CoinsTime int
}
//保存已经连接的终端的对象
var nodes []Node
//通过pos共识算法选择矿工
func chooseWinner() string {
var Pool []string
//根据持币时间把对应的矿工地址存放到数组中
for i := 0; i < len(nodes); i++ {
node := nodes[i]
Pool = append(Pool, node.Addres)
}
if len(Pool) != 0 {
//通过随机值找到挖矿的矿工
rand.Seed(time.Now().Unix())
r := rand.Intn(len(Pool))
workerAddr := Pool[r]
return workerAddr //返回矿工地址
}
return "noMiner" //无矿工的时候默认为noMiner
}
//使用通道实现线程间通信
var communication = make(chan string)
func main() {
fmt.Println("Hello PoS!")
/* test
genesisBlock := genesisBlock()
newBlock := generateNextBlock(genesisBlock, 1)
generateNextBlock(newBlock, 2)
for i := range Blockchain {
fmt.Println(Blockchain[i])
}
*/
genesisBlock := genesisBlock()
currentBlock := genesisBlock
fmt.Println("genesisBlock:", genesisBlock)
//通过终端连接到PoS服务
//创建监听
netListen, err := net.Listen("tcp", "192.168.120.54:1234") //此处ip为本机器ip,端口为1234
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer netListen.Close()
go func() {
//通过矿工实现区块挖矿
rand.Seed(time.Now().Unix())
for {
w := <-communication
//fmt.Println(w)
//将新的区块利用w矿工添加到数组中
currentBlock = generateNextBlock(currentBlock, rand.Intn(1000), w) //区块数据此处随机为0-1000,实际为默尔克树的hash
fmt.Println("newBlock:", currentBlock)
}
}()
go func() {
//每隔10s选择一次矿工
for {
time.Sleep(10 * time.Second)
winner := chooseWinner()
fmt.Println("PoS choose winner:", winner)
//将矿工放入到通道中
communication <- winner
}
}()
//等待连接
for {
conn, _ := netListen.Accept()
connAddr = append(connAddr, conn)
//扫描终端
scanbalance := bufio.NewScanner(conn)
io.WriteString(conn, "please input holding period:\n") //终端中输入持币周期
//扫描终端里写了什么
go func() {
//在子线程中扫描终端中的内容
for scanbalance.Scan() {
txt := scanbalance.Text()
fmt.Println("\nTerminal holding period:", txt)
//通过时间戳创建地址
addr := calculateHash(time.Now().String()) //此处暂时把时间的hash作为终端用户的hash
coins, _ := strconv.Atoi(txt)
node := Node{addr, coins}
//将连接的终端放在数组中
nodes = append(nodes, node)
fmt.Println("usr number:", len(nodes))
for i := 0; i < len(nodes); i++ {
fmt.Println("addr:", nodes[i].Addres, "CoinsTime:", nodes[i].CoinsTime)
}
}
}()
}
}
//此时可以通过telnet ip 1234连接到PoS服务器,终端输入信息回车后,即可发送到svr
//telnet 192.168.120.54 1234
通过telnet ip port分别先后添加币龄为11和21的用户,运行结果:
E:/Software/Golang/go1.11/bin/go.exe run c6_PoS.go [E:/Code/Golang/gongshi]
Hello PoS!
genesisBlock: {0 0 00prehash fffed895b697b36811ebb8f485ba6fba4d5a40cad51788ebc8f3315b0a7185d8 2019-01-23 14:57:24.7674002 +0800 CST m=+0.002000001 00}
PoS choose winner: noMiner
newBlock: {1 524 fffed895b697b36811ebb8f485ba6fba4d5a40cad51788ebc8f3315b0a7185d8 d36bb430282351a1596952140d14432e89d0faa75b592eef7ab2d6f7bb49ea36 2019-01-23 14:57:34.7754002 +0800 CST m=+10.010000001 noMiner}
Terminal holding period: 11
usr number: 1
addr: 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3 CoinsTime: 11
PoS choose winner: 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3
newBlock: {2 460 d36bb430282351a1596952140d14432e89d0faa75b592eef7ab2d6f7bb49ea36 e7cf8e22fde1f6ab71bf1c848902d5f1f3df63753e0740854e292a1bf7c6dc42 2019-01-23 14:57:44.7754002 +0800 CST m=+20.010000001 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3}
PoS choose winner: 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3
newBlock: {3 540 e7cf8e22fde1f6ab71bf1c848902d5f1f3df63753e0740854e292a1bf7c6dc42 59ca95145cc84bfe206e8765241c4a02a81cf1a7d1fb0f460a7b489542bb35a5 2019-01-23 14:57:54.7754002 +0800 CST m=+30.010000001 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3}
Terminal holding period: 21
usr number: 2
addr: 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3 CoinsTime: 11
addr: b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969 CoinsTime: 21
PoS choose winner: b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969
newBlock: {4 389 59ca95145cc84bfe206e8765241c4a02a81cf1a7d1fb0f460a7b489542bb35a5 26d0abb4e4a5e4b9be9406ac1b5b8be38f8a325c9e35b6fbc3624a429c04689f 2019-01-23 14:58:04.7754002 +0800 CST m=+40.010000001 b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969}
PoS choose winner: 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3
newBlock: {5 604 26d0abb4e4a5e4b9be9406ac1b5b8be38f8a325c9e35b6fbc3624a429c04689f e61436f01c6176e5646196e4a01902b65dae9685cc36c5341145d0ea4c12cda3 2019-01-23 14:58:14.7754002 +0800 CST m=+50.010000001 719ac8ceb8f6139972ada537da6a19156ad9a3eafdcc068368018be443a6cfc3}
PoS choose winner: b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969
newBlock: {6 821 e61436f01c6176e5646196e4a01902b65dae9685cc36c5341145d0ea4c12cda3 f4506431b849a0a7774632b9c0ecc055b5582a06c7b9afa82d757a4f119e2462 2019-01-23 14:58:24.7754002 +0800 CST m=+60.010000001 b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969}
PoS choose winner: b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969
newBlock: {7 756 f4506431b849a0a7774632b9c0ecc055b5582a06c7b9afa82d757a4f119e2462 ed710738d44a811bf06daaa4d2b2ddbef6322909d1960a5a38222ad9a60f3dc1 2019-01-23 14:58:34.7754002 +0800 CST m=+70.010000001 b0c6cb4989a1ec71c9014fdff0f50ee0d89462b19b498ce04de616e2d515a969}
exit status 1
错误: 进程退出代码 1.
结果表明,未添加终端用户的时候默认使用noMiner进行挖矿,添加币龄为11的用户后,其挖矿为币龄11的用户了,继续添加币龄为21的用户,其挖矿根据PoS随机为11和21两用户之一。
3、说明
本代码当前测试环境为golang1.11。