来用Python写个Toy BlockChain

Posted by szh on 2019-06-23

前言

为了学习一下区块链技术,外加熟悉一下 python,我决定自己写一个区块链项目。之前写的东西要么是在框架下进行,要么是功能不是很完整,这是头一回自己从底下写起来。简单考虑了一下,对编写方式大概有一点想法,先要搭一个简单的测试环境,然后从最简单的立马可以看到效果的地方写起,一点一点的实现完整的功能,在写之前要先考虑好设计并写进这篇文章中,然后每一个功能写完了都尽可能进行单元测试。

基本的选型

  • 网络通信方面采用 Rumor-Mongering 的 Gossip 协议
  • 共识协议采用基本的 POW,后期可能会考虑加入 Ghost 协议
  • 采用账户模型而不是 UTXO(账户模型实现起来更方便一些,但是为了防止重放攻击需要添加 Nonce,这使得交易无法并发执行,但是一些分组处理的策略可以改善这种情况)
  • 状态维护的数据结构上采用 Merkel Patricia Tree 维护账户状态和所有交易,持久化上采用 leveldb
  • 开始阶段不支持脚本或智能合约,在后期会加入图灵完备的合约语言以及 VM

测试环境

测试环境主要是在本机上模拟一群节点,一部分是矿工,负责处理交易生成区块、验证区块、更新状态,另一部分是用户(轻节点),可以发起交易并进行简单支付验证(SPV),由于在本机进行,网络通信可能并不会真正进行,而是由一个消息系统模拟,因此,测试环境由以下两部分构成:

  • 事件系统:一方可以向事件系统注册对某一事件的回调函数,另一方可以向系统触发一个事件,系统会调用有关的回调函数,目前支持以下方法:

    • dispatchEvent():触发一个事件,系统将调用所有注册的回调函数(可能在调用过程中阻塞)
    • dispatchEventOnUser():触发一个事件,指定用户得到回调
    • registEvent():用户向事件系统对某一事件注册回调函数
      目前事件系统仅由两个哈希表嵌套构成,外层以事件名称为键,内层以用户 ID 为键
  • 模拟网络:模拟网络环境以及其中可能发生的情况,调用了事件系统,目前支持以下方法:

    • sendTo():向一个用户发送信息,触发对该用户的固定事件,无延迟

在目前的测试环境中,交易由全节点随机发起。

整体结构设计

  • 全节点和轻节点为类,在测试环境中可产生多个实例,节点包括以下部分:
    • Gossip 协议处理层,负责处理所有网络信息,检测或进行数字签名(不符合要求的信息被直接丢弃,否则下传接受进一步处理),维护一份 peer 列表
    • 核心协议处理层,负责验证交易和区块,打包/同步区块
    • 数据库层,对账户和交易分别维护 MPT 并由 leveldb 持久化
  • 控制台指令处理为全局单例,处理用户输入并向指定节点对象发送信息
  • 事件系统为全局单例,处理所有由网络或用户指令产生的消息
  • 网络系统为全局单例,可配置模拟网络环境或使用 socket 的真实网络环境

进度规划

  • 基本的能成链看效果的功能,包括:

    • 只根据区块高度、上一个区块的 Hash 是否正确和时间戳判断是否接受区块
    • 没卵用的空壳交易,不进行交易验证
    • 保存在内存中无法持久化的区块记录
    • 随机乱发只根据距离衰减的 Gossip 协议
  • 完整的基础功能,包括:

    • 数字签名
    • 全节点可持久化的 MPT 用于记录账户信息和交易信息
    • 完善的账户模型和交易验证
    • 完善的区块数据结构,在之前的基础上加入 POW、交易根、状态根、出块奖励以及交易列表
    • 完善的 Gossip 协议
    • 解决区块分叉和同步问题
  • 进阶的功能,包括:

    • Ghost 协议
    • 并发的交易验证
    • 轻节点以及 SPV
  • 目前水平难以达到的功能,包括:

    • 图灵完备的区块链脚本语言及智能合约

开发日志 & 一些想法

区块貌似可以只包括 Merkel 树根节点 Hash 和一份固定交易列表,矿工在验证区块时相当于进行状态机复制,给定固定的交易顺序,所有节点应该得到一致的账户树和交易树,这样就无需在区块中保存维护树形结构所需的信息,而只需保存两个根哈希以进行 SPV。