你愿意阅读这篇文章,是因为你对加密货币的崛起感到兴奋,你想知道它们背后的基层技术——区块链是怎样运作的。
但想要了解区块链并不是一件易事,至少于我而言是这样的。在艰难跋涉般浏览了大量的视频并学习很多教程后,我开始亲手进行实践。
我喜欢通过动手来学习,它迫使我从代码层来了解区块链的本质,如果你也做同样的事情,在学习完这个指南之后,你就会扎实地掌握区块链的基本运作原理。
在你开始之前……
记住,我们所谓的区块链,是一种由不易篡改的数据区块,按顺序链接而形成的记录账本。它们可以包含交易、文件或任何你想要的数据。重要的是,它们被链接到一起的过程,是使用了哈希(hash)。
如果你并不清楚哈希是什么鬼,这篇文章会给你一个很好的解释。
这篇指南文章面向的读者是?你应该能熟练阅读并能编写基本的Python语言,并且能够对 HTTP请求的工作原理有一些了解,因为我们会通过HTTP来和我们的区块链对话。
我需要准备些什么?确保你安装了Python 3.6+ 。你还需要安装Flask以及 Requests library:
pip install Flask==0.12.2 requests==2.18.4
哦,对了,你还需要一个 HTTP客户端,例如Postman或者cURL 。当然,其他的客户端也是可以的。 最终的代码在哪里?这里可以找到:https://github.com/dvf/blockchain
步骤一:构建一个区块链
打开你最喜欢的文本编辑器或IDE,我个人喜欢用PyCharm。创建一个新的文件,并命名为blockchain.py 。我们只使用一个文件,但如果你搞丢了它,你可以随时引用源代码。 我们创建了一个区块链类,其构造函数创建了一个初始空列表(存储我们的区块链),而另一个则用于存储交易。下面是我们的类设计大纲:
区块链类设计大纲
我们的区块链类负责管理这个区块链。它将用于存储交易,并具有一些辅助方法为区块链添加新区块。让我们开始执行一些方法。 一个区块看起来是怎样的? 每一个区块都有一个索引
,一个时间戳
( Unix时间),一系列交易
,一个证明
(稍后会提到),以前之前区块的哈希
。 下面就是一个区块所包含的一些信息:在这一点上,区块链的概念应该是明显的,每一个新区块除了其本身的信息,还包括之前区块的哈希。这是关键的,因为是它使得区块链不可更改:如果攻击者破坏了区块链当中之前的一个区块,那么所有后续的区块都会包含不正确的哈希。 这有什么用吗?如果你觉得没有,花一点时间好好思考一下,这是区块链背后的核心理念。 将交易添加到一个区块当中 我们需要一种方式将交易添加到一个区块当中。我们的new_transaction()
代码就是负责做这个的,它也是非常简单的:在 new_transaction()
指令将一笔交易添加到列表后,它会返回添加交易区块(也就是下一个有待挖出的区块)的索引。之后,这对于提交交易的用户而言是有用的。 创建新区块 当我们的区块链部署完之后,我们需要生成创始区块(最初的区块)来启动它。我们还需要为我们的创始区块添加一个“证明”,也就是挖矿的结果(或者说工作量证明)。我们之后会谈到更多关于挖矿的问题。 除了用我们的构造函数来创建创始区块,我们还会详细了解 new_block()
, new_transaction()
和 hash()
:上述的代码应该说是简单的,我添加了一些注释和文档字符串,让代码更容易阅读。我们几乎完成了区块链的构造部分工作。但在这一点上,你一定想知道新的区块是如何创建或者挖取的。 理解工作量证明(pow) 所谓工作量证明,就是发现一个解决数学问题的字符串。这个字符串必需很难找到,但易于被网络上的所有人所验证。这就是工作量证明背后的核心思想。 我们来看看一个非常简单的例子,帮助你去理解工作量证明。 我们决定,某些整数x
乘以另一个整数y
的哈希,其结果的末尾必需是0.所以, hash(x * y) = ac23dc...0
。为了简化,我们把x设为5.然后用Python来实现它:
from hashlib import sha256
x = 5
y = 0 # We don't know what y should be yet...
while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
y += 1
print(f'The solution is y = {y}')
在这里的解, y = 21 ,因此,其生成的哈希末尾为0:
hash(5 * 21) = 1253e9373e...5e3600155e860
在比特币当中,它的工作量证明算法被称为Hashcash(哈希现金算法)。这个算法和我们上述的基本例子没有太多的区别。在这个算法下,矿工为创建一个新区块而去争相解决这个新的解。矿工们在得出这个新解之后,就会收到比特币代币的奖励。
网络可以很容易地验证它们的解。
部署基本的工作量证明
让我们来为区块链部署一种类似的算法。我们的规则将类似于上面的例子:
想要调整算法的难度,我们可以修改前导零的数字。不过4就已经足够了。你会发现,加上一个前导零,就会导致找到一个解所需的时间大为不同。
我们的类几乎已经完成了,我们准备开始用HTTP请求来进行交互。
步骤二:区块链作为一个API
我们要使用的是Python Flask框架。这是一个微框架,这让我们可以通过HTTP请求来和我们的区块链谈话。
我们有三种创建方式:
- /transactions/new 为一个区块创建一笔新的交易;
- /mine告知我们的服务器挖取一个新区块
- /chain来返回整个区块链
设置Flask
我们的“服务器”将在我们的区块链网络中形成一个单一节点。让我们创建一些样板代码:
以上代码的部分说明:
第15行:实例化我们的节点。你可以在这里阅读更多关于Flask的信息:http://flask.pocoo.org/docs/0.12/quickstart/#a-minimal-application
第18行:为我们的节点创建一个随机名称
第21行:实例化我们的区块链类
第24-26行:创建/mine 端点,这是一个GET 请求;
第28-30行:创建 /transactions/new 端点,这是一个POST请求,因为我们会把数据发送给它;
第32-38行:创建/chain 端点,它会返回整个区块链;
第40-41行:在端口5000上运行服务器;
交易端点
这是一笔交易请求的样子,它是用户发给服务器的信息:
{
"sender": "my address",
"recipient": "someone else's address",
"amount": 5
}
因为我们已经有了添加区块交易的类,剩下的工作就很容易了。让我们来编写下添加交易的函数:
挖矿端点
我们的挖矿端点是魔法所发生的地方,实际上它也很容易。它要做的是三件事:
- 计算工作量证明
- 通过一笔交易授予矿工(我们)代币,以作为奖励;
- 创造新区块,并将其添至区块链;
注意,挖取区块的接收方正是我们的节点地址。到了这一步,我们可以说已经完成了,可以开始和我们的区块链进行交互。
步骤3:和我们的区块链进行交互
你可以使用普通的 cURL或者Postman来交互我们的API 。
启动服务器:
$ python blockchain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
让我们试着通过一个 GET 请求挖取一个区块
http://localhost:5000/mine:
使用Postman 来创建一个GET请求
让我们通过创建一个 POST请求来创建一笔新的交易
http://localhost:5000/transactions/new
其包含着我们的交易结构:
使用Postman来创建一个POST请求
如果你使用的并不是Postman,那么你可以使用cURL来创建等效的请求;
$ curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 5
}' "http://localhost:5000/transactions/new"
我重新启动了我的服务器,并挖取了两个区块,使得总共挖取的区块数为3.
让我们通过http://localhost:5000/chain: 请求来检查整个区块链:
{
"chain": [
{
"index": 1,
"previous_hash": 1,
"proof": 100,
"timestamp": 1506280650.770839,
"transactions": []
},
{
"index": 2,
"previous_hash": "c099bc...bfb7",
"proof": 35293,
"timestamp": 1506280664.717925,
"transactions": [
{
"amount": 1,
"recipient": "8bbcb347e0634905b0cac7955bae152b",
"sender": "0"
}
]
},
{
"index": 3,
"previous_hash": "eff91a...10f2",
"proof": 35089,
"timestamp": 1506280666.1086972,
"transactions": [
{
"amount": 1,
"recipient": "8bbcb347e0634905b0cac7955bae152b",
"sender": "0"
}
]
}
],
"length": 3
}
步骤4:共识
这是非常酷的一部分。我们已经有了一个接受交易的基础区块链,它允许我们挖取新的区块。但区块链的灵魂在于它要实现去中心化。如果其实现了去中心化,我们究竟如何才能确保所有参与者所用的链是相同的呢?这就是所谓的共识问题,如果我们想要网络当中存在多个节点,我们就必须部署一种共识算法。
注册新节点
在我们部署一种共识算法之前,我们需要一种让节点能够识别网络相邻节点的方法。我们网络上的每一个节点,应该有网络其他节点的登记表。因此,我们需要更多的端点:
1 、 /nodes/register
来接受一系列URL形式的新节点;
2、 /nodes/resolve
来部署我们的共识算法,其负责解决任何冲突,确保节点所在的链是正确的。
我们需要修改我们的区块链构造函数,并为注册节点提供一个方法:
注意,我们使用了一个set()
来持有节点列表。这是一种确保新添加的节点是幂等的的廉价方法。这意味着无论我们添加一个特定的节点多少次,其出现的次数都只有1 。
部署共识算法
如前所述,冲突是当一个节点与另一个节点所在的链不同时的情况。为了解决这个问题,我们将制定一条规则,即最长有效链是权威链。换句话说,网络上最长的链就是有效的区块链。使用这种算法,我们网络中的节点之间就达成了共识。
第一种方法valid_chain()
是通过遍历每个区块并验证哈希和证明,其负责检查一条链是否是有效的;
resolve_conflicts()
则是遍历所有我们的相邻节点,下载它们的链,并使用上述方法来验证它们。如果一个有效链被找到了,其长度要高于我们所在的链,我们就用这个新链取代我们所在的旧链。
让我们将这两个端点注册到我们的API中,一个用于添加相邻节点,另一个用于解决冲突:
在这一点上,如果你喜欢的话,你可以使用不同的机器,并在你的网络上启动不同的节点。或者你可以使用相同的机器,使用不同的端口来启动程序。我在我的机器上用不同的端口启动了另一个节点,并用我目前的节点进行了注册。因此,我有了两个节点:
http://localhost:5000
和 http://localhost:5001
.
注册一个新节点
然后我在节点2上挖取了一些新的区块,确保链更长。之后,我在节点1上调用GET /nodes/resolve
函数,然后节点1所在的链就被共识算法替换成节点2的链了。
你也可以找一些朋友,帮你一起测试你的区块链……
我希望这能够启发你创造出新的东西。我相信,区块链会迅速改变我们思考经济、政府以及记录的方式。
原文发布时间为:2018年03月28日
本文作者:智能计算时代
本文来源:CSDN区块链大本营,如需转载请联系原作者。