1.新建main.go文件

package mainimport ("bufio""crypto/sha256""encoding/hex""encoding/json""fmt""io""log""math/rand""net""os""strconv""sync""time""github.com/davecgh/go-spew/spew"    //spew包将区块链输出到终端"github.com/joho/godotenv"           //godotenv从前面的.env文件中读取配置信息
)
// Block represents each 'item' in the blockchain
type Block struct {Index     intTimestamp stringBPM       intHash      stringPrevHash  stringValidator string                     //由原先的difficulty改为了现在validator,即记账节点的地址
}// Blockchain is a series of validated Blocks
var Blockchain []Block
var tempBlocks []Block
// tempBlocks是临时存储单元,在区块被选出来并添加到BlockChain之前,临时存储在这里// candidateBlocks handles incoming blocks for validation
var candidateBlocks = make(chan Block)
//chan建立的是一个fifo队列,fifo先进先出
//candidateBlocks 是 Block 的通道,任何一个节点在提出一个新块时都将它发送到这个通道// announcements broadcasts winning validator to all nodes
var announcements = make(chan string)
// announcements也是一个通道,主Go TCP服务器将向所有节点广播最新的区块链var mutex = &sync.Mutex{}
//是一个标准变量,允许我们控制读/写和防止数据竞争// validators keeps track of open validators and balances
var validators = make(map[string]int)
//validators 是节点的存储地址,同时也会保存每个节点持有的令牌数//calculateBlockHash函数将一个block的所有字段连接到一起后,再调用 calculateHash 将字符串进行求hash。
// SHA256 hasing
// calculateHash is a simple SHA256 hashing function
func calculateHash(s string) string {h := sha256.New()h.Write([]byte(s))hashed := h.Sum(nil)return hex.EncodeToString(hashed)
}//calculateBlockHash returns the hash of all block information
func calculateBlockHash(block Block) string {record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHashreturn calculateHash(record)
}//与前一个区块的hash值,生成区块
func generateBlock(oldBlock Block, BPM int, address string) (Block, error) {var newBlock Blockt := time.Now()newBlock.Index = oldBlock.Index + 1newBlock.Timestamp = t.String()    //时间戳newBlock.BPM = BPMnewBlock.PrevHash = oldBlock.HashnewBlock.Hash = calculateBlockHash(newBlock)newBlock.Validator = addressreturn newBlock, nil
}//验证区块内容
// isBlockValid makes sure block is valid by checking index
// and comparing the hash of the previous block
func isBlockValid(newBlock, oldBlock Block) bool {if oldBlock.Index+1 != newBlock.Index {return false}if oldBlock.Hash != newBlock.PrevHash {return false}if calculateBlockHash(newBlock) != newBlock.Hash {return false}return true
}func handleConn(conn net.Conn) {defer conn.Close()
//defer语句延迟执行一个函数,该函数被推迟到当包含它的程序return时再执行。go func() {for {msg := <-announcements  //通道的值赋给msgio.WriteString(conn, msg)}}()var address string   // 验证者地址,即Validator的地址// 验证者输入他所拥有的 tokens,tokens 的值越大,越容易获得新区块的记账权// allow user to allocate number of tokens to stake// the greater the number of tokens, the greater chance to forging a new blockio.WriteString(conn, "Enter token balance:")scanBalance := bufio.NewScanner(conn)  //在终端输入获取token余额
// 允许验证者输入他持有的令牌数量,然后,该验证者被分配一个 SHA256地址,随后该验证者地址和验证者的令牌数被添加到验证者列表validators 中。for scanBalance.Scan() {  // scanBalance.Scan()遇到 \n 或者\r\n循环一次,每输入一行内容必须回车,退出循环按组合键 Ctrl +Dbalance, err := strconv.Atoi(scanBalance.Text())  //strconv包实现字符串到数字的转换if err != nil {log.Printf("%v not a number: %v", scanBalance.Text(), err)return}t := time.Now()address = calculateHash(t.String())validators[address] = balance
//余额赋给validators集合,集合的键值为其地址即哈希值,address为对时间序列求的hash值,防止有相同的addressfmt.Println(validators)break}io.WriteString(conn, "\nEnter a new BPM:")scanBPM := bufio.NewScanner(conn)   //BPM可以看作区块上要记录的数据go func() {for {// take in BPM from stdin and add it to blockchain after conducting necessary validationfor scanBPM.Scan() {bpm, err := strconv.Atoi(scanBPM.Text())// if malicious party tries to mutate the chain with a bad input, delete them as a validator and they lose their staked tokens
//对作恶者进行惩罚(即输入),删除他作为一个记录者的权利,并扣除他的余额if err != nil {log.Printf("%v not a number: %v", scanBPM.Text(), err)delete(validators, address)
//delete()函数从map中删除一组键值对,delete(map, 键)conn.Close()}mutex.Lock()   //互斥锁,即在一个并发进程中,加锁中的语句只能在解锁后再执行,不能并发同时执行oldLastIndex := Blockchain[len(Blockchain)-1]mutex.Unlock()// create newBlock for consideration to be forgednewBlock, err := generateBlock(oldLastIndex, bpm, address)if err != nil {log.Println(err)continue}if isBlockValid(newBlock, oldLastIndex) {candidateBlocks <- newBlock}io.WriteString(conn, "\nEnter a new BPM:")}}}()//一直输出区块信息数据// simulate receiving broadcastfor {time.Sleep(time.Minute) //休眠1分钟mutex.Lock()output, err := json.Marshal(Blockchain)mutex.Unlock()if err != nil {log.Fatal(err)}io.WriteString(conn, string(output)+"\n")}}//选择获取记账权的节点
// pickWinner creates a lottery pool of validators and chooses the validator who gets to forge a block to the blockchain
// by random selecting from the pool, weighted by amount of tokens staked
func pickWinner() {time.Sleep(30 * time.Second)  //休眠30秒钟mutex.Lock()temp := tempBlocksmutex.Unlock()lotteryPool := []string{}if len(temp) > 0 {// slightly modified traditional proof of stake algorithm// from all validators who submitted a block, weight them by the number of staked tokens// in traditional proof of stake, validators can participate without submitting a block to be forgedOUTER:for _, block := range temp {// if already in lottery pool, skipfor _, node := range lotteryPool {if block.Validator == node {continue OUTER}}// lock list of validators to prevent data racemutex.Lock()setValidators := validatorsmutex.Unlock()k, ok := setValidators[block.Validator]if ok {for i := 0; i < k; i++ {lotteryPool = append(lotteryPool, block.Validator)}}}// randomly pick winner from lottery pools := rand.NewSource(time.Now().Unix())    //time.Now().Unix()将时间戳转化为时间格式
//rand.NewSource()生成伪随机数 time.Now().Unix()为种子值
// 使用当前的时间生成一个随机源,也就是随机种子r := rand.New(s)// 生成一个randlotteryWinner := lotteryPool[r.Intn(len(lotteryPool))]
//r.Intn 返回一个随机的格式化后的时间n,0 <= n <=len(lotteryPool)// add block of winner to blockchain and let all the other nodes knowfor _, block := range temp {if block.Validator == lotteryWinner {mutex.Lock()Blockchain = append(Blockchain, block)mutex.Unlock()for _ = range validators {announcements <- "\nwinning validator: " + lotteryWinner + "\n"}break}}}mutex.Lock()tempBlocks = []Block{}mutex.Unlock()
}func main() {err := godotenv.Load()if err != nil {log.Fatal(err)}// create genesis block
//初始化创世区块t := time.Now()genesisBlock := Block{}genesisBlock = Block{0, t.String(), 0, calculateBlockHash(genesisBlock), "", ""}spew.Dump(genesisBlock)
//使用spew.Dump 这个函数可以以非常美观和方便阅读的方式将 struct、slice 等数据打印在控制台里,方便我们调试。Blockchain = append(Blockchain, genesisBlock)
//将创世区块添加到结构体数组Blockchain中// start TCP and serve TCP serverserver, err := net.Listen("tcp", ":"+os.Getenv("ADDR"))   //os.Getenv()从文件中获取环境变量if err != nil {log.Fatal(err)}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)}
}

2.新建 .env文件,并写入以下代码

ADDR=9000

3.运行main.go文件

export GOPATH=/home/go
go run main.go

4.进入9000端口

nc localhost 9000

go语言实现PoS共识机制相关推荐

  1. pos共识机制_OK区块链60讲 | 第17集:什么是PoS共识机制

    什么是PoS共识机制https://www.zhihu.com/video/1196092110837805056 <OK区块链60讲>是由OKEx&新浪科技联合出品的区块链科普动 ...

  2. pos共识机制_PoS共识机制是什么?其优缺点分别是什么?

    PoS共识机制的全称是Proof of Stake.PoS机制通过计算每个节点所占代币的比例和时间,等比例的降低挖矿难度,从而加快找随机数的速度.以太坊采用的PoS则是Casper投注共识,通过保证金 ...

  3. POS共识机制竟然漏洞这么多 | 分析POS共识机制的原理带来的思考

    序言 上文深入比特币.以太坊源码带你解读POW共识机制我们学习探讨了POW共识机制,看完得童鞋们应该就知道POW是有几大缺点的:出块慢,共识时间长.开销大等等,那么有没有其它的共识机制能够解决这些问题 ...

  4. 通俗讲解:PoW共识机制与以太坊的关系、Ghost协议 及 Casper PoS共识机制的变种...

    作者:林冠宏 / 指尖下的幽灵 掘金:juejin.im/user/587f0d- 博客:www.cnblogs.com/linguanh/ GitHub : github.com/af9133374 ...

  5. 通俗讲解:PoW共识机制与以太坊的关系、Ghost协议 及 PoS共识机制的变种---Casper...

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  6. 这可能是全网最简单的POS共识机制算法

    共识算法是区块链非常重要的一种算法,简单来说,共识算法就是为了使网络中的节点得到一致的认可.就比如说合作双方达成一致,共同遵守某个合约. 传统的分布式系统中,由于有着中心服务器进行统一管理,各个子服务 ...

  7. 以太坊的POS共识机制(二)理解 Serenity :Casper

    Original post by Vitalik Buterin, on December 28th, 2015 特别感谢Vlad Zamfir,他提出了按块达成共识这个想法,并且说服我认同它和Cas ...

  8. 区块链共识机制:POW、POS、DPOS、PBFT、POOL

    共识机制作为区块链的关键技术之一,在业务吞吐量.交易速度.不可篡改性.准入门槛等等方面发挥重要的作用. 区块链是去中心化的,没有中心记账节点,所以需要全网对账本达成共识.目前有POW.POS.DPOS ...

  9. 北卡罗来纳大学教授王永革:基于拜占庭协议的PoS是共识机制未来的发展方向...

    "基于拜占庭协议(BFT)的PoS克服了PoW的先天缺陷,是共识机制未来的发展方向" 本文旨在传递更多市场信息,不构成任何投资建议. 8月20日,由火星财经主办的"POW ...

最新文章

  1. 从五个经典工作看语义SLAM
  2. Nature Method:Bioconda解决生物软件安装的烦恼
  3. 带你测试对比深度学习框架!TensorFlow,Keras,PyTorch...哪家强?(附数据集)
  4. Openwrt MiniDLNA 安装方法及 其需要的依赖关系
  5. Win32 API 获取其他程序剪贴板内容
  6. 【阿里云课程】模型设计之动态网络,原理与设计
  7. spring日志报错提醒_使用爬虫框架htmlunit整合springboot出现的一个不兼容问题
  8. QT实现共享内存进行进程间通信
  9. 『中级篇』Docker-Stack部署投票应用(50)
  10. shuffle洗牌算法java_js打乱一个数组 的 洗牌(shuffle )算法
  11. 差分隐私 python_[宜配屋]听图阁
  12. 10_文件包含漏洞(属于任意代码执行)
  13. C#读写注册列表(写入注册列表,读取注册列表的数据)
  14. elipse与数据库Mysql连接,并实现创建数据表的功能
  15. git.exe push --progress origin master:master To https://192.168.3.145:10102/r/~lifan/tms-vue.git !
  16. 分享一下我在东方时尚学车的经历
  17. Python中 or 和 and 用法
  18. antd页面多表单校验
  19. android 拦截鼠标按键
  20. 第十讲:Python爬取网页图片并保存到本地,包含次层页面

热门文章

  1. 核范数和l1范数_L1范数与L2范数的区别
  2. 不兼容android5.1.1,Android5.1.1启动问题
  3. 用c语言实现顺序查找,顺序查找算法及C语言实现
  4. 使用 Vue 从零开始手写一个猫咪瀑布流组件
  5. linux小白微信群,用linux文件处理三剑客将微信群成员导出的方法
  6. 【安全-前端】XSS、XSRF
  7. airtest连接小米mix3不成功
  8. 鸿蒙大陆鸿蒙战凯,鸿蒙大陆10.2正式版
  9. 【Windows】更换笔记本键盘操作
  10. 国产手机 android 6,小米5/魅族PRO 6/华为P9横评:国产Android手机大比拼