banner
leaf

leaf

It is better to manage the army than to manage the people. And the enemy.

自己的第一个区块链——基于Python

Python 是一门简单易学、语法优美且功能强大的编程语言。它拥有一个自由开放的社区环境,该社区提供了诸如 Web、爬虫、数据分析、机器学习等方面的开发框架和类库,可直接使用进行快速开发。另外,Python 代码也被称为是可执行伪代码,好的 Python 代码就像伪代码一样,干净、简洁、一目了然,所以这里选择 Python 作为开发语言实现一个区块链原型。

Python 是一种广泛使用的高级编程语言,由荷兰人由吉多・范罗苏姆发明,第一版发布于 1991 年。之所以选中 Python 作为这门开发语言的名字,是因为范罗苏姆是 BBC 电视剧《Monty Python》的爱好者,故选取了 Python 一词作为这门语言的名字。范罗苏姆对 Python 的定位是 “优雅”“明确”“简单”,

所以 Python 程序语法简单易懂,即使是编程初学者,也能轻易上手,而且 Python 内置了丰富的数据结构和类库,即便是初学者也能通过 Python 轻松实现功能非常复杂的程序。

Python 开发者的理念是:用一种方法,最好是只有一种方法来做一件事,这种理念深刻体现在 Python 程序的设计中。在开发 Python 程序时,如果面临多种选择,Python 开发者一般会拒绝花哨的语法,而选择明确没有或者很少有歧义的语法。这些 Python 程序开发中的准则被称为 “Python 之禅”。Python 开发者蒂姆・彼得斯对 “Python 之禅” 的总结如下。

●Beautiful is better than ugly. 美比丑好。

●Explicit is better than implicit. 直言不讳比心照不宣好。

●Simple is better than complex. 简单比内部复杂更好。

●Complex is better than complicated. 内部复杂比外部复杂好。

●Flat is better than nested. 平面的比嵌套的好。

●Sparse is better than dense. 错落有致比密密匝匝的好。

●Readability counts. 可读性很重要。

●Special cases aren’t special enough to break the rules. 特殊情况不能特殊到打破规律。

●Although practicality beats purity. 虽然实用比纯粹更重要。

●Errors should never pass silently. 永远别让错误悄悄地溜走。

●Unless explicitly silenced. 除非是你故意的。

●In the face of ambiguity,refuse the temptation to guess. 碰到模棱两可的地方,绝对不要去作猜测。

●There should be one——and preferably only one——obvious way to do it. 什么事情都应该有一个,而且最好只有一个显而易见的解决办法。

●Although that way may not be obvious at first unless you’re Dutch. 一开始并不容易,因为你不是 Python 之父(这里 Dutch 指 Python 之父)。

●Now is better than never. 现在就开始要比永远都不做好。

●Although never is often better than right now. 很多时候永远都不做要比匆匆忙忙去做要好。

●If the implementation is hard to explain,it’s a bad idea. 如果一个想法实现起来很困难,那它本身就不是一个好想法。

●If the implementation is easy to explain,it may be a good idea. 如果一个想法实现起来很容易,那它或许就是一个好想法。

●NameSpaces are one honking great idea——let’s do more of those!名字空间是个了不起的想法,所以我们现在就开始吧。

这些准则让 Python 开发者倾向于注重简单,避免复杂,更加关注如何高效地解决问题,是值得每个开发者思考和遵循的。

下面让我们开始进入 Python 的世界,首先要做的是搭建一个 Python 开发环境。

1.Python 安装

Python 的安装过程比较简单,前往 Python 官网:https://www.python.org/downloads/ 下载对应操作系统的 Python 安装文件进行安装即可,Python 安装文件的下载页面如示。

1)选择 Python 代码编辑器

首先是选择一款合适的 Python 代码编辑器。

工欲善其事,必先利其器。虽然说用操作系统中自带的文本编辑器,比如记事本这种编辑器也可以用来编写 Python 代码,但这样的编辑器没有代码高亮、自动补全和代码错误提示等功能,会大大降低开发效率。所以,需要选择一款功能比较全面的 Python 代码编辑器,这样可以有效地提升开发效率和代码质量。这里对 PyCharm、Sublime Text 3、Visual Studio Code、Atom、Jupyter Notebook 等这几个主流的 Python 代码编辑器做一下简单比较,读者可结合自己的需求选择一款适合自己的编辑器。

●PyCharm,专门面向 Python 的全功能集成开发环境。不论是在 Windows、Mac OS X 系统中,还是在 Linux 系统中都可以快速安装和使用。PyCharm 中集成了与 Python 开发相关的编辑、调试、代码管理等各项功能,打开一个新的文件就可以开始编写代码。PyCharm 启动的时候稍微有点慢,比较适合开发和管理大型项目

Atom 的下载地址是 https://atom.io/。

●Jupyter Notebook,是一款网页版的 Python 编辑器,可以在浏览器中编写和执行代码,执行结果会以 HTML 等富媒体格式进行展示。另外,Jupyter Notebook 还支持使用 LaTeX 编写数学公式和使用 Markdown 编写文档。

Jupyter Notebook 无须额外下载安装文件,只需要在终端(Linux 和 Mac OS)或命令行窗口(Windows)下使用 Python 包管理工具进行安装即可,安装命令如下:

pip install jupyter

本书将使用 Jupyter Notebook 进行 Python 代码的开发和调试。

介绍完编辑器后,再简单了解一下 Python 的包管理工具。

(2)安装 Python 包管理工具

目前最流行的 Python 包管理工具是 pip 命令,当使用 Python 安装文件安装完成后,pip 也会一起安装到系统中。

image

其他的命令可以使用 pip­help 进行查看,如图所示。

image

介绍了包管理工具以后,再来了解一下 Python 的虚拟环境。

(3)创建 Python 虚拟环境

在 Python 的开发过程中需要安装第三方包和依赖库,而开发不同的项目需要安装的包和依赖库通常各不相同。为了防止不同的应用之间包和依赖库冲突,最好能创建一个独立的 Python 开发环境,也就是 Python 的虚拟环境。这样可以使每个项目的环境与其他项目独立开来,保证开发环境不受其他项目影响,解决包冲突的问题。而创建独立环境的方法就是使用虚拟环境管理工具。

当前最流行的 Python 虚拟环境管理工具叫 virtualenv,它是 Python 的一个第三方工具。安装命令如下:

pip install virtualenv

安装完成后就可以创建一个独立的 Python 虚拟开发环境了。将这个虚拟环境命名为 venv,创建命令是 virtualenv venv -p python3,其中 “-p python3” 是指定 python 的版本为 python 3。

image

要使用这个虚拟环境需要先用 source venv/bin/activate 命令将其激活,激活成功后会在当前行的最前面显示当前虚拟环境的名字

image

至此,当前的 Python 开发环境就是前面创建的 venv 这个虚拟环境了。若想退出当前虚拟环境,可使用 deactivate 命令进行操作,退出后(venv)这个虚拟环境的名字也会消失,

4)Jupyter Notebook 的启动和使用

下面在 Python 虚拟开发环境中安装 jupyter 并启动 Jupyter Notebook,安装和启动 Jupyter Notebook 的命令及执行过程如图 4-12 和图 4-13 所示,启动命令是 jupyter notebook。

图 4-12  安装 jupyter

图 4-13  启动 Jupyter Notebook

启动 Jupyter Notebook 后会自动在浏览器中打开一个页面(启动后程序默认监听 8888 端口),如图 4-14 所示。

image

该页面显示的是 “Files” 标签下的内容,其中列出当前文件夹下的文件目录结构,第 2 个标签 “Running” 显示的是当前运行的 notebook 页面,第 3 个标签 “Clusters” 显示的是集群功能。要编写 Python 代码可以选择右上角的 “New” 菜单,在下拉框中选择 “Python 3” 来新建一个 notebook 页面,如图 4-15 所示。

image

新建的 notebook 页面主要可分为 4 块区域,名称、菜单栏、工具条和编辑区域,如图 4-16 所示。

image

图 4-16 Jupyter Notebook 编辑页面

标题默认是 “Untitled”,可以通过双击标题位置对其进行修改,菜单栏包括了所有对 notebook 的操作,工具条显示的是常用的命令。

下面开始编写第一个 Python 程序。

3. 第一个 Python 程序

第一个 Python 程序的功能比较简单,就是输出 “你好,区块链” 这几个字,使用 Python 中的打印函数 print 函数实现,输入代码 print(“你好,区块链”)后,单击 “工具条” 上的 “Run” 按钮或使用快捷键<Shift+Enter>执行代码,如图 4-17 所示,可以看到下面打印了结果 “你好,区块链”。

image

区块包括区块头和区块体两个部分,区块头由版本、父区块哈希值、数据、Merkle 根、时间戳、目标难度、Nonce 值组成;区块体实际上可以包含任何内容,在比特币中包括交易输入数量、交易输出数量和长度不定的交易记录等信息。在以太坊中的区块体中除了交易数据还包含智能合约。为方便开发和理解,这里要开发的区块链系统简化了区块的结构,只使用最关键的几个字段,其他非必要的字段先忽略。简化后的区块包括父区块哈希值、数据、时间戳、哈希值这四个字段,区块的哈希值由区块中父区块哈希值、数据和时间戳这 3 个字段拼接起来通过哈希算法计算而成。通过 Python 定义区块的结构,如图

image

(2)定义区块链的结构

区块链是由区块组成的链条,定义了区块的结构后还需要定义一个区块链的结构。将各个区块通过哈希值前后依次相连,然后将这些区块都放到一个数组中,初始化时列表为空,新的区块依次放到这个列表中,再定义一个函数来实现向这个列表中添加区块的功能,从而定义了这个区块链的结构

image

区块链结构

以上就完成了最简单的区块链结构,下面在此基础上一步步对其完善直至实现一个真正的区块链系统。

(3)实现区块链原型

1)先来创建第 1 个区块,或者叫作创世区块,代码如图 4-34 所示,创世区块没有父区块,所以 prev_hash 的值为空。

image

2)再创建两个区块,数据是关于张三的转账记录,prev_hash 依次是前一个区块的哈希值,如图

image

3)然后新建一个区块链并将上面的区块添加到区块链中,如图 4-36 所示。

image

4)最后打印输出当前区块链的信息,可以看到这个区块链包含了 3 个区块,如图

image

以上就实现了一个最简单的区块链原型,但它缺少了区块链的核心功能,比如共识机制、账户和交易、去中心化网络等,不能算是一个真正的区块链。接下来会在这个原型基础上一步步添加区块链的各种特性,直至实现一个完整的区块链。首先是为其加入共识机制 —PoW(工作量证明)

共识机制是区块链技术的重要组成部分,在 3.1 共识机制中已经介绍过常见的几种共识机制。这里将使用 Python 实现比较简单的 PoW,即工作量证明机制。PoW 的原理是通过不断计算,直到找到一个随机数(Nonce)的值使得生成的哈希值满足一定的条件,如图

image

下面我们将工作量证明机制加入上面的区块链原型中。

1)首先更新区块的结构,加入 Nonce 字段,如图

image

2. 哈希算法库

在 Python 中已经内置了一个哈希库 ——hashlib,它提供了常见的哈希算法,如 MD5,SHA256 等,以下为 MD5 和 SHA256 的使用方法,如图所示。

image

Base64 是一种用 64 个字符来表示任意二进制数据的方法,Python 中内置了 Base64 库以供使用,下面内容是将字符串 “你好,区块链” 进行 Base64 加密和解密的过程,代码如图

image

在 Python 中使用非对称加密算法,比如椭圆曲线算法时,需要安装第三方库。在此简单讲解如何在 Python 中使用椭圆曲线算法。要用椭圆曲线算法,需要先安装第三方库 ECDSA,安装命令命令如下:

pip install ecdsa

安装完成后先导入算法库,生成一对私钥和公钥,然后用私钥进行签名,用公钥进行签名验证,如图 4-29 所示,先使用 SigningKey.generate()方法生成一个私钥,由这个私钥可以生成一个唯一的公钥。然后使用私钥对 “Something” 这个字符串生成签名,而由私钥生成的公钥就可以用来验证这个签名是否正确

image

最后介绍 Python 的绘图库 Matplotlib,这个库用来生成常用的图表和进行数据可视化。Matplotlib 支持各种平台,并且功能强大,能够轻易绘制出各种专业的图形。要使用这个库需要先进行安装,安装命令如下:

pip install matplotlib

Matplotlib 库的使用方法如图

image

已详细介绍过区块的结构,区块包括区块头和区块体两个部分,区块头由版本、父区块哈希值、数据、Merkle 根、时间戳、目标难度、Nonce 值组成;区块体实际上可以包含任何内容,在比特币中包括交易输入数量、交易输出数量和长度不定的交易记录等信息。在以太坊中的区块体中除了交易数据还包含智能合约。为方便开发和理解,这里要开发的区块链系统简化了区块的结构,只使用最关键的几个字段,其他非必要的字段先忽略。简化后的区块包括父区块哈希值、数据、时间戳、哈希值这四个字段,区块的哈希值由区块中父区块哈希值、数据和时间戳这 3 个字段拼接起来通过哈希算法计算而成。通过 Python 定义区块的结构,如图

image

区块链是由区块组成的链条,定义了区块的结构后还需要定义一个区块链的结构。将各个区块通过哈希值前后依次相连,然后将这些区块都放到一个数组中,初始化时列表为空,新的区块依次放到这个列表中,再定义一个函数来实现向这个列表中添加区块的功能,从而定义了这个区块链的结构,具体代码如图

image

以上就完成了最简单的区块链结构,下面在此基础上一步步对其完善直至实现一个真正的区块链系统。

(3)实现区块链原型

1)先来创建第 1 个区块,或者叫作创世区块,代码如图 4-34 所示,创世区块没有父区块,所以 prev_hash 的值为空。

image

2)再创建两个区块,数据是关于张三的转账记录,prev_hash 依次是前一个区块的哈希值,如图

image

3)然后新建一个区块链并将上面的区块添加到区块链中,如图所示。

image

4)最后打印输出当前区块链的信息,可以看到这个区块链包含了 3 个区块,如图所示。

image

几个重要的共识机制曾提到,在工作量证明的计算过程中,“挖矿” 的计算量很大,而验证的方法很简单,计算量很小。从上图中的代码中也可以看到,“挖矿” 消耗的时间为 1.42s,而验证时间只需要 0.026s(26μs),很明显验证比计算工作量证明简单得多。

4)完成工作量证明机制后,再生成一个新的加入工作量证明机制的区块链,如图所示。

image

将上述区块链的区块信息打印出来可以看到,区块的哈希值都是以 “00000” 开头,如图所示。

image

已经介绍过区块链技术中账户其实就是区块链网络中的一个地址,用来标示区块链网络中的某个结点。而钱包是用来存放账户的工具。账户的本质是一对唯一的私钥和公钥,也就是说钱包的本质是生成和管理这些密钥对的工具。以下是创建钱包、账户并实现其交易功能的步骤。

(1)创建钱包及账户

首先定义一个 Wallet 的类用来代表钱包,Wallet 初始化时会生成一对唯一的私钥和公钥,即一个账户,生成的算法基于椭圆曲线算法,具体代码如图所示。

image

2)生成签名

创建账户后还需要提供这个账户的地址和公钥并利用账户的私钥生成签名。其中,地址由公钥先经哈希算法再进行 Base64 算法计算而成,签名生成的是一串二进制字符串,为便于查看,这里将这个二进制字符串转换成 ASCII 字符串进行输出,具体代码如图

image

账户的地址、公钥和签名

(3)生成验证函数

然后还需要实现一个验证函数用来验证签名是否正确,生成验证函数的代码如图

image

(4)测试钱包的功能

接下来对钱包功能进行测试,包括:账户的生成、账户的地址、公钥信息以及签名功能是否正常,如图 4-48 所示。

基于上面的公钥和签名,可验证签名的正确性,如图所示,代码执行的返回结果为 True,说明这个签名是基于和这个公钥配对的私钥生成的,也就是说钱包(账户)功能正常。

image

image

钱包和账户的功能实现后还需要加入交易的功能。为了支持交易,这里需要再定义一个交易的数据结构。

在前面的步骤中,区块结构中的数据只是一个简单的字符串,而在实际的区块链中,数据是一个个的交易记录,这些交易记录需要包含交易的发送方、接收方、交易数量,以及用来验证交易的发送方公钥和发送方签名,这里定义一个包含这几个字段的 Python 类 Transaction,如图

image

(6)整合钱包和交易功能

完成了钱包和交易的功能后,将这两个功能更新到前面完成的区块链原型中。

1)首先,将区块结构中的数据替换为交易列表,如图

image

2)接着,在工作量证明中添加奖励机制,这个奖励机制为挖矿成功后可以获得加密数字货币作为奖励。这里假定为每完成一个区块可获得 1 个加密数字货币,代码如图

image

3)然后,为了方便获取区块链中账号的加密数字货币情况,这里再添加一个名为 get_balance 的查询函数,该函数会遍历整个区块链的交易数据,通过匹配账号获取与这个账号相关的所有交易记录,然后累加这个账号接收到的金额,并减去所有的支出金额,计算出该账户的当前余额,如图

image

7)测试区块链交易功能

最后来测试一下区块链的交易功能能否正常运行。先初始化一个空的区块链和 3 个钱包账户(alice、tom、bob),如图所示,可以看到初始化钱包中余额都是 0。

image

下面假设 alice 生成了创世区块并将创世区块添加到区块链中。根据工作量证明机制,alice 将获得 1 个加密数字货币,代码

image

alice 获得奖励后可以向 tom 进行转账,这里转账了 0.3 个加密数字货币,代码如图

image

假设这笔转账交易被广播到区块链网络后由 bob 进行验证并生成一个新的区块添加到了网络上,那么 bob 也将获得 1 个加密数字货币,代码如图

image

再次打印此时的钱包余额。此时可以看到 alice 转给 tom 0.3 个加密数字货币后变成了 0.7 个,tom 因此拥有 0.3 个加密数字货币,bob 挖矿获得了 1 个加密数字货币。如图

image

至此,这个区块链系统可以支持挖矿奖励和交易的功能了!但实际的区块链是运行在一个去中心化网络中的,在下一节中,将实现一个简单的去中心化的区块链网络。

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.