本文首发于万向区块链旗下“万云Wancloud”微信公众号。
2018年的门刚打开,区块链的火就烧成了火焰山。徐小平放言要拥抱区块链,朋友圈刷屏不止,连上班地铁上都能听到区块链,一夜起,区块链成了茶前饭后的谈资。于是乎,那个经常听到的问题又开始抓耳挠腮:区块链到底是什么鬼?关注的订阅号不停推送“一篇文章让你搞懂区块链”,“三分钟Get区块链”等不尽相同的内容,声音从四面八方聚焦到你耳边。
万云也在思考能为想了解区块链的老铁们做点什么,鉴于已有如此多区块链概念普及文,此次我们不聊枯燥的概念,而是回归区块链“技术”,一步步认真教你获得一个属于自己区块链。放心,只要你稍微懂一点技术,你就可以实现并拥有它。
|| 以下翻译自Daniel van Flymen的《Learn Blockchains by Building One》,有所删改。
|| 原文地址:
前言
概念了解:在开始前你需要知道,区块链是一种按时间将数据区块以顺序相连的方式组合在一起的链式数据结构,并通过密码学来保证其不可篡改和不可伪造的分布式账本。这些区块可以包含交易、文件以及任何你想要的数据,重要的是它们通过哈希链接在一起。
目标读者:可以轻松地阅读和编写一些基本的Python,并且对HTTP有一些了解。
所需工具:Python 3.6+、Flask、Requests:
pip install Flask==0.12.2 requests==2.18.4
除此之外还需安装HTTP工具,如Postman、cURL。
源代码地址:
第一步:建立区块链
①实现一个Blockchain类
打开一个你常用的文本编辑器或者IDE,新建一个blockchain.py的python文件,并创建一个Blockchain类,在构造函数中创建两个空的队列,一个用于存储区块链,另一个用于存储交易。下面是Blockchain类的模板代码:
我们所创建的Blockchain类将用来管理链,它会存储交易,并且提供一些方法来帮助添加新的区块到链。下面是详细的实现方法。
每个区块所包含5个基本属性:index,timestamp (in Unix time),交易列表,工作量证明和前一个区块的哈希值。我们来看一个例子:
到这里,我们对于链的概念应该比较清楚了,每个新的区块都会包含上一个区块的哈希值,从而让区块链具有不可篡改的特性。如果攻击者攻击了链中比较靠前的区块,则所有后面的区块将包含不正确的哈希值。如果不能理解,慢慢消化——这是理解区块链技术的核心思想。
②将交易添加到区块
接下来我们实现一个将交易添加到区块的方法,继续看代码:
在new_transaction()方法中向列表中添加一笔交易之后,它返回值是本次交易的index,该index会被添加到下一个待挖掘区块,后面在用户提交交易时也会用到。
③建一个新的区块
当Blockchain被实例化后,我们需要创建一个创世区块,同时为我们的创世区块添加一个工作量证明,这是挖矿的结果,我们稍后会详细讨论挖矿。
除了创建创世区块的代码,我们还需要补充new_block(),new_transaction()和hash()的方法:
到此,我们的区块链已经基本上实现了雏形。这时候,你肯定想知道新区块是怎么被挖出来的,也就是我们通常所说的“挖矿”。
④什么是工作量证明?
想了解什么是“挖矿”,就必须理解工作量证明(POW)是什么。区块链上每一个新的区块都来自于工作量证明(POW),POW的目标是计算出一串解决问题的数字,这个结果众所周知是很难计算的,但却十分容易验证,因为网络上的任何人都能够验证这个结果,这是“工作量证明”背后的核心思想。
我们来看一个非常简单的例子帮助理解:
假设整数X乘以另一个整数y的哈希值必须以0结尾,hash(x * y) = ac23dc...0. 设x = 5.求y。我们用Python来实现:
得到的答案是当y = 21,哈希值的结尾为0:
在比特币中,工作证明算法被称为Hashcash,这和我们上面所举的例子差不多,结果难于发现却易于校验。Hashcash是矿工为了创建一个新区块而争相计算的问题,计算难度通常取决于字符串中搜索的字符数,通常也会花费一定的时间才能计算得到,最终计算出来的矿工们会通过交易获得一定数量的比特币作为奖励。
⑤实现一个基本的工作量证明
首先我们为Blockchain类实现一个类似的算法:
规则:找到一个数字p,使得它与前一个区块的 proof 拼接成的字符串的 Hash 值以 4 个零开头。
通过修改前导零的数量,可以调整算法的难度,但是4个零完全足够了。你会发现,每当增加一个前导零,找到一个对应的解决方案与所需的时间之间会产生巨大的差异。
进行到这里,我们的Blockchain类已经基本完成,接下来我们实现HTTP服务进行交互。
第二步:区块链API
我们将使用Python Flask框架,Flask是一个轻量级的Web应用框架,这使我们可以通过web服务来调用Blockchian类。
①创建三个API:
•/ transactions / new为区块创建一个新的交易
•/mine告诉我们的服务器开采新的区块。
•/chain返回整个区块链。
②使用Flask
我们的“服务器”将基于Flask框架来实现区块链网络中的一个节点。 我们来添加一些模板代码:
以下是对上面添加的内容的进行简要说明:
Line15:实例化Flask web服务节点。
Line18:为我们的服务节点创建一个随机的名称。
Line21:实例化Blockchain类。
Line24-26:创建一个路由为/mine的GET请求的,调用后端Blockchain的new block方法。
Line28-30:创建一个路由为/transactions/new的POST请求,将数据发送给后端Blockchina的new transaction方法。
Line32-38:创建一个路由为/chain的GET请求,将返回整个链。
Line40-41:在端口5000上运行服务器。
③实现交易
下面是用户发起交易时发送到服务器的请求:
由于我们已经有了将交易添加到区块的方法,接下去就十分容易了。
下面我们来实现添加交易的函数:
④实现挖矿
我们的挖矿方法是魔法发生的地方。它十分容易,只做三件事情:计算工作量证明;通过新增一笔交易奖励矿工一定数量的比特币;创建新的区块并将其添加到链中来。
需要注意的是,开采块的交易接收者是我们自己服务器节点的地址,我们在这里所做的大部分工作只是与Blockchain类进行交互,基于以上我们区块链已经完成了,接下来开始交互演示。
第三步:交互演示
您可以使用cURL或Postman与API进行交互。
启动服务器:
尝试通过向http:// localhost:5000 / mine发出GET请求来挖掘区块:
创建一个新的交易,向http://localhost:5000/transactions/new发出一个POST请求:
也可以使用cURL发送请求:
以上仅为交互演示的示例,你可以在你自己所完成的区块链上进行更多尝试。
第四步:共识机制
我们有一个基本的区块链可以进行交易和挖矿,但其实区块链更重要的意义在于它们是分布式的。那么我们需要确保所有的节点都运行在同一条链上,这就是回归到了共识问题,如果要满足在网络上有多个节点并且不断增加,我们必须要实现共识算法。
①注册新的节点
在实现共识算法之前,需要找到一种方式让网络上的节点知道其相邻的节点,每个节点都需要存储网络上其他节点的记录。因此,我们需要新增几个方法来帮助实现:
1./nodes/register接受URL形式的新节点列表。
2. / nodes / resolve来执行我们的共识算法,它可以解决任何冲突,确保节点具有正确的链。
下面我们将修改Blockchain的构造函数以提供注册节点的方法:
注意,我们使用set()集合来保存节点列表,这是确保新节点的添加是幂等的简便方法,这意味着无论我们添加特定节点多少次,它都只会出现一次。
②实现共识算法
如前所述,当一个节点与另一个节点有不同时会发生冲突,为了解决这个问题,我们遵循取最长链原则,通过使用此算法,让网络中的节点间达成共识。
valid_chain()负责检查一个链是否有效,具体方法是循环读取每个区块并验证哈希和证明。
resolve_conflicts()负责循环读取所有相邻节点,获取它们的链并使用上面的方法验证它们的有效性。如果找到了一个更长的有效链,则取代我们当前的链。
我们将两个方法注册到我们的API中,一个用于添加相邻节点,另一个用于解决冲突:
最后,如果你愿意的话可以开启另一台机器,并在你的网络上运转不同的节点。或者使用同一台机器上的不同端口启动进程。我在我的机器的不同端口创建另外一个节点,并将其注册到当前区块链网络中。 因此,我有两个节点:http:// localhost:5000和http:// localhost:5001。
为了确保链更长,我在节点2上挖掘了一些新的区块。 之后,我在节点1上调用GET / nodes / resolve,此处的链已经被共识算法计算后的得到的新链所替代。
现在,你可以邀请一些朋友来一起测试你的区块链了。
本文教程到此结束,那么,属于你自己的区块链撸好了吗?别忘了分享给身边同为程序员的朋友,一起来撸区块链!