外文发表日期: 2018-04-14
外文链接:https://medium.com/coinmonks/code-a-simple-p2p-blockchain-in-go-46662601f417
在之前的文章中,我们已经知道了怎么编写PoW也知道了IPFS怎么工作, 但是有一个致命的缺点,我们的服务都是中心化的,这篇文章会教你怎么实现一个简单的完全去中心化的P2P网络。
背景知识
什么是P2P网络
在真正的P2P架构中,不需要中心化的服务来维护区块链的状态。例如,当你给朋友发送比特币时,比特币区块链的“状态”应该更新,这样你朋友的余额就会增加,你的余额就会减少。
在这个网络中,不存在一个权力高度中心化的机构来维护状态(银行就是这样的中心化机构)。对于比特币网络来说,每个节点都会维护一份完整的区块链状态,当交易发生时,每个节点的区块链状态都会得到更新。这样,只要网络中51%的节点对区块链的状态达成一致,那么区块链网络就是安全可靠的,具体可以阅读这篇一致性协议文章。
本文将继续之前的工作,200行Go代码实现区块链, 并加入P2P网络架构。在继续之前,强烈建议你先阅读该篇文章,它会帮助你理解接下来的代码。
开始实现
编写P2P网络可不是开开玩笑就能简单视线的,有很多边边角角的情况都要覆盖到,而且需要你拥有很多工程学的知识,这样的P2P网络才是可扩展、高可靠的。有句谚语说得好:站在巨人肩膀上做事,那么我们先看看巨人们提供了哪些工具吧。
喔,看看,我们发现了什么!一个用Go语言实现的P2P库go-libp2p!如果你对新技术足够敏锐,就会发现这个库的作者和IPFS的作者是同一个团队。如果你还没看过我们的IPFS教程,可以看看这里, 你可以选择跳过IPFS教程,因为对于本文这不是必须的。
警告
目前来说,go-libp2p
主要有两个缺点:
1. 安装设置比较痛苦,它使用gx作为包管理工具,怎么说呢,不咋好用,但是凑活用吧
2. 目前项目还没有成熟,正在紧密锣鼓的开发中,当使用这个库时,可能会遇到一些数据竞争(data race)
对于第一点,不必担心,有我们呢。第二点是比较大的问题,但是不会影响我们的代码。假如你在使用过程中发现了数据竞争问题,记得给项目提一个issue,帮助它更好的成长!
总之,目前开源世界中,现代化的P2P库是非常非常少的,因为我们要多给go-libp2p
一些耐心和包容,而且就目前来说,它已经能很好的满足我们的目标了。
安装设置
最好的环境设置方式是直接clone libp2p
库,然后在这个库的代码中直接开发。你也可以在自己的库中,调用这个库开发,但是这样就需要用到gx
了。这里我们使用简单的方式,假设你已经安装了Go:
- go get -d github.com/libp2p/go-libp2p/…
- 进入go-libp2p
文件夹
- make
- make deps
这里会通过gx包管理工具下载所有需要的包和依赖,再次申明,我们不喜欢gx,因为它打破了Go语言的很多惯例,但是为了这个很棒的库,认怂吧。
这里,我们在examples
子目录下进行开发,因此在go-libp2p
的examples下创建一个你自己的目录
- mkdir ./examples/p2p
然后进入到p2p文件夹下,创建main.go
文件,后面所有的代码都会在该文件中。
你的目录结构是这样的:
好了,勇士们,拔出你们的剑,哦不,拔出你们的main.go
,开始我们的征途吧!
导入相关库
这里申明我们需要用的库,大部分库是来自于go-libp2p
本身的,在教程中,你会学到怎么去使用它们。
package main
import (
"bufio"
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
"io"
"log"
mrand "math/rand"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/davecgh/go-spew/spew"
golog "github.com/ipfs/go-log"
libp2p "github.com/libp2p/go-libp2p"
crypto "github.com/libp2p/go-libp2p-crypto"
host "github.com/libp2p/go-libp2p-host"
net "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
ma "github.com/multiformats/go-multiaddr"
gologging "github.com/whyrusleeping/go-logging"
)
spew
包可以很方便、优美的打印出我们的区块链,因此记得安装它:
- go get github.com/davecgh/go-spew/spew
区块链结构
记住,请先阅读200行Go代码实现区块链, 这样,下面的部分就会简单很多。
先来申明全局变量:
// Block represents each 'item' in the blockchain
type Block