导言

欢迎查阅 Tendermint 指南!本指南是新手学习 Tendermint 最好的材料

什么是 Tendermint?

Tendermint 是一种能够为多台机器安全和保证数据一致性复制应用程序的软件。从安全性层面看,分布式系统中即使 1/3 的随机节点即使宕机了,Tendermint 依然能够保证分布式系统正常运行。另外在数据一致性方面,故障的节点能够看到相同的事务日志并计算出相同的状态。安全且保持一致性复制是分布式系统的基本问题,在很多应用程序中起着关键性的作用,比如货币系统、选举和基础设备编排等系统。

分布式系统需具备容忍节点离线或出错,也就是拜占庭容错。拜占庭容错理论历史悠久,区块链技术落地成功的案例、比如比特币、以太坊的成功促使该理论在计算机领域的实现得以流行。区块链技术着重结合对等网络(P2P) 和密码认证对拜占庭容错加以进化。交易被批量打包成块,每个块通过加密哈希连接上一个块从而形成链,这也是把该技术命名为 区块链 (BlockChain) 的原因。

Tendermint 包含两个组件: 区块链共识引擎 (blockchain consensus engine)、 通用应用接口 (generic application interface)共识引擎被称为 Tendermint Core ,确保交易记录在任何一个节点都能一致被排序。通用应用接口被称为 应用区块链接口 (Application BlockChain Interface) 简称为 ABCI ,交易能够被任何编程语言处理。大部分区块链和共识方案预先打包内置状态机(比如存储键值对或者通过脚本),而开发者通过 Tendermint 可以对任意编程语言编码的应用实现 BFT 状态机复制,并且开发环境对开发者也很适合。

Tendermint 以易用、易懂、高性能为设计原则,对各种分布式应用程序都有用。

Tendermint 与同类软件对比

Tendermint 与两类软件相似。一类是分布式键值对存储软件,例如 Zookeeper, etcd, 和 consul, 但他们使用了 non-BFT 共识。另外一类就是区块链技术。区块链技术包含加密货币,例如比特币和以太坊,还包含非传统类的分布式账本,譬如 Hyperledger 的 Burrow

Zookeeper, etcd, consul

Zookeeper, etcd 和 consul 都是典型的键值对存储和 non-BFT 共识算法的实现。Zookeeper 使用 Zookeeper Atomic Broadcast 版本的 Paxos 算法;etcd 和 consul 使用比较新和简单的 Raft 共识算法。非拜占庭容错共识实现的分布式集群中,假设包含 3-5 个节点,可以允许一半的节点离线,但是如果出现一个拜占庭错误节点(作恶节点)足以摧毁该分布式系统。

三者都各有特色稍微不同地实现了键值对存储,但都重点围绕着给分布式系统提供基础服务,例如动态配置、服务发现、锁、领导节点选举 (leader-election)

Tendermint 和上述类型的软件本质作用差不错,但有两个重要的不同点:

  • 支持拜占庭容错算法,意味着智能容忍三分之一以内的节点错误,这个错误包括任意节点离线和节点作恶
  • 独立于特定类型软件,例如键值存储类。而 Tendermint 只是关注任意状态机复制,开发者根据软件需求业务逻辑,例如通过状态机复制实现键值对存储、加密货币乃至分布式电子投票平台等分布式应用。

比特币、以太坊及其他加密货币

Tendermint 诞生于传统的加密货币之后。相比于比特币的工作量证明 (Proof of Work) ,它实现的共识算法更高效和安全。早期的 Tendermint 内置了简单的数字货币并实现了共识功能。节点需要缴纳保证金,如果作恶保证金就会被没收。Tendermint 实际上也是一种股权证明 (Proof of stake)

加入可股权证明算法之后,Tendermint 演变为区块链共识引擎,允许任何机器都可以加入作为节点的分布式系统。这也意味这 Tendermint 可以作为其他区块链项目即插可用的共识引擎,替换原有的共识模块。也就是说,举个例子你可以使用 Tendermint 共识运行任何语言实现的以太坊节点源码作为 ABCI 应用(上文提到,最终实现了一种基于股权证明共识以太坊。事实上,我们基于以太坊实现了上述的 demo

the Cosmos network 共识算法就是内置了 Tendermint

其他区块链项目

Fabric 采用了与 Tendermint 相似的方法,但是它更偏向于如何管理状态,并要求所有的应用行为能够运行在 docker 容器中,我理解Fabric 的 chaincode 就像以太坊的智能合约。它基于 PBFT 实现。在 Tendermint 中,可以把这种基于容器的行为作为 ABCI 应用。

Burrow 实现了以太坊虚拟机和交易机制,并扩展了名字注册 (name-registery),许可权限、原生合约提供多种方式调用区块链接口 (REST 和 JSON-RPC)。它使用 Tendermint 作为共识引擎,提供的特殊的应用状态(这里的状态由账户、验证人集合、和名字注册)

ABCI 概述

通用区块链接口 ABCI 允许任意类型编程语言编写的拜占庭容错复制类的应用程序。

初衷

迄今为止,实现区块链的源码都是一个巨大的应用(译者注:这里的说法有点绝对,17 年国内有一家公司开源的 CITA 代码把区块链各个功能模块拆分单独部署),也就是一个应用包含了所有的功能模块,包含 P2P 网络,"mempool" 广播交易,共识模块,账户余额,图灵完备的合约模块和用户用户权限模块等。

CITA将单个节点按照功解构为交易共识、合约引擎、链 式存储、网络同步、服务网关等多个松耦合的微服务,一方面利用云计算基础设 施来按需提升性能,另一方面,各个组件可独立替换升级。

一个软件代码过于庞大会导致组件复用和维护过于复杂,特别是当代码模块封装不够好的情况下更糟糕;

另外会限制大一统架构会限制编程语言的使用,譬如在以太坊中,它支持图灵完备的字节码虚拟机,它限制开发者必须要可以编译为那种类型字节码的语言,当前只有 Serpent 和 Solidity 满足。

所以,基于上述两种缺陷,Tendermint 从特定区块链应用(例如 Bitcoin-core 和 go-ethereum) 的把共识引擎和 P2P 网络分离。区块链应用的细节抽象为一个接口,并通过 socket 协议实现。

所以就有了接口的概念,通用区块链接口 (ABCI) , 和实现接口的 Tendermint Socket Protocol (简称为: TSP 或 Teaspoon)

ABCI 介绍

Tendermint Core 也就是共识引擎,通过 一种满足 ABCI 规范的 socket 协议和应用通信。

用比特币作为例子,比特币加密货币区块链中每个节点都维护一份公链完整的所有未交易输出数据库。如果想要在 ABCI 上实现一个比特币类(Bitcoin-like)的系统,Tendermint 将会负责:

  • 在节点间共享区块和交易
  • 给所有交易建立一个规范且不可篡改的顺序

而区块链应用 (也就是 bitcoin-coer) 负责:

  • 维护 UTXO 数据库
  • 验证交易的加密签名
  • 阻止交易花费尚未存在的交易
  • 允许客户端查询 UTXO 数据库

Tendermint 在应用(例如 Bitcoin-core) 进程和共识进程之间提供简单的接口(例如 ABCI),以此分解庞大的区块链应用软件。

ABCI 由三种主要的消息类型组成,这些消息类型从 Tendermint-core 发往区块链应用(例如 bitcoin-core),应用会对消息作出对应的响应。

消息的详细说明可查阅:ABCI Message Types

DeliverTx 是应用中的很重要组成部分,它会传递链中的每笔交易。应用(例如 Bitcoin-core)需根据当前状态,应用程序协议和交易的加密凭证来验证来自 DeliverTx 消息传递过来的每笔交易。每笔被验证通过的交易然后更新应用的状态,例如存储交易键值对,或更新 UTXO 数据库。

CheckTx 消息和 DeliverTx 类型相似,但它只是验证交易的有效性。Tendermint Core mempool 首先通过 CheckTx 检测交易的有效性,然后将有效的交易转发给它的节点。例如,一个应用的验证规则为检测交易的递增序列号,如果序列号是旧的,则 CheckTx 返回错误。

Commit 消息用以给当前应用状态计算加密保证 (cryptographic commitment),加密保证被放入下一个区块头。节点状态更新不一致表明链出现分叉。加密保证同时简化了安全的轻节点客户端开发,因为 Merkle-hash 证明可以通过检测区块哈希去验证是否正确,而区块已被 quorum 签名。

多个 ABCI socket 可以连接到同一个应用上,Tendermint Core 新建三个 ABCI 连接应用:一个用以验证被广播到 mempool 中的交易;另一用以共识引擎去运行新区块提议;最后一个 socket 连接被用于查询应用状态。

显然在开发区块链底层链时,开发者要对消息处理需十分严谨。但是 Tendermint 的 ABCI 的三种消息模型架构给消息处理提供了很不错的范例。下图展示了 ABCI 的消息流:

abci.png

关于确定性的说明

区块链处理交易的逻辑必须是确定的,否则 Tendermint Core 复制的节点之间将不会达成共识。

在以太坊平台选用 Solidity 开发区块链应用是很好的选择,除其他因素外,它是一个完全确定的编程语言(也就是在各种环境下输出都一样,与之相反的例子就是普通编程语言多线程竞争问题导致输出不确定),然而通过普通的编程语言如果知遵循规范话(譬如避免线程竞争),也是可以做到在各种条件下同一输入会得到确定的输出。游戏程序员和区块链开发者对在不确定的的情况情景下开发最终确定的程序比较熟悉,例如:

  • 生成随机数 (使用确定的种子)
  • 线程竞争条件(避免多线程)
  • 系统时钟
  • 未初始化的内存 (in unsafe programming languages like C or C++)
  • 浮点数计算
  • 随机的语言特性(例如 Go 中迭代 Map 也是随机的)

谨慎编码可以避免写出不确定输出的代码,同时创造特殊的语法检测器或静态分析器检测确定性也是行得通的。将来我们团队可能会开发这样的工具。

共识概述

Tendermint 是一种易懂,大部分都是异步和拜占庭容错的共识协议。它遵循的的一个简单的状态机,如下图所示:

consensus_logic.png

协议中的角色称谓 验证人 ;他们轮流对交易的区块提议并对提议的区块投票。区块被提交到链上,且每个区块就是一个区块高度。但是区块也有可能不被提交到链上,面临这种情况时,协议将继续下一轮对区块提议和投票,有权提议新块的验证人可以为当前区块高度选择区块并对其投票,然后剩下的认证人投票,超过 2/3 的验证人对同一个块投票即可提交该区块。验证人对一个提议的区块进行预投票和预提交当超过 2/3 的验证人在同一轮提议中对同一个块投票,那么这个区块才会被提交。

[这段在扯淡,不翻译]

验证人面临当前的提议者离线或者网络延迟,则会出现提交区块失败的情况。Tendermint 允许验证人确认出现故障的验证人可以被忽略。在进行下一轮投票之前,所有验证人等待一小段时间接收提议者完成对块的提议。验证人依赖超时才进行下一轮操作体现了 Tendermint 是部分同步的协议,而非全异步协议。完成对区块提议之后,协议剩下的部分是完全是异步的,验证人只要接收到超过 2/3 的验证人集时就放弃当前一轮投票,执行下一步操作。Tendermint 足以简单是因为提交区块也使用了上述的机制,当超过三分之二的节点成功对提议的区块投票时就表示区块已经被提交,剩下的马上转入下一个区块的提议和投票。

假设少于三分之一的验证有主观恶意,Tendermint 共识算法就能保证系统安全。也就是说,多个验证人永远不会在同一高度提交区块造成区块冲突。Tendermint 确保系统安全是通过引入 锁定 规则,一旦验证者预提交了一个区块,那么该验证人就会被锁定在这个区块。然后:

  1. 该验证人必须在预提交的区块进行预投票
  2. 当前一轮预提议和预投票若没成功提交区块,该验证人就会被解锁,然后进行对新块的下一轮预提交

Stake

在很多系统中,并不是所有的验证人都在共识协议中有中同样的投票权重。因此我们对 1/3 或 2/3 的验证人并不十分感兴趣,而是关心所有投票的占比,这个比例对于单个验证人并不是均匀分布的,在数字货币系统中,可以依据币量和币龄分配投票权重。

因为 Tendermint 可以使用现有的区块链项目作为 ABCI ,所以可以给基于 Tendermint 实现的系统定义一套数字货币,然后根据各个节点持有的币量(根据持有币的数量或者持币的币龄也可,在这需根据业务来定)计算节点的投票权重。当投票权是基于节点持有的数字货币作为依据,那么这样的系统就成称为股权证明 (Proof of stake)。节点通过把持有的币作为保证金之后就成为验证人,如果作恶,这笔保证金就会被销毁。这就给协议的安全性加了经济的因素,就像比特币系统中的工作量证明依赖矿机算力一样,增强了区块链网络的安全性,同时也可量化违反共识的成本,想要控制股权证明的分布式区块链网络,必须控制超过全网超过 2/3 的投票权重。

Cosmos Network 内置了加密货币的 ABCI 应用,使用股权证明机制

tm-transaction-flow.png