简单了解 Tendermint
Tendermint 是什么?
来自一段 slack 对话
先来举个例子,Wordpress 与 Apache Web Server,Apache Web Server 通过 fastcgi
与 Wordpress 进行交流。它们被组合到一个服务端的进程中,这个进程负责处理连接逻辑,比如控制流量和安全。Tendermint 就像是分布式账本中的 Apache Web Server,它负责了像 p2p 网络,共识,交易广播等等之类的事情。
对于应用任何商业性质的逻辑处理而言,Tendermint 是透明的。而对 Tendermint 来说,这些逻辑处理也都只不过是二进制的字节而已。一旦网络中的验证人对一个块达成共识,并且想要提交这个块时,交易就会通过 ABCI 被推送到应用中,ABCI 是一个网络套接字协议,它的作用就类似于在 Apache Web Server 与 Wordpress 示例中的 fastcgi
. 没有人知道谁会成为未来分布式账本中的 Wordpress.
另一种解释
Tenermint 是一个软件,用于在多台机器安全一致地复制一个应用。所谓安全,指的是即使有多达 1/3 的机器出现任意故障的情况下, Tendermint 仍然能够正常工作。所谓一致,指的是每一个正常工作的机器都会有着同样的交易日志,计算相同的状态。安全一致的复制是分布式系统中一个至关重要的问题:从货币到选举,到基础设施规划,它在广泛应用的容错中承担了一个极其重要的角色。
能够容忍机器以任何一种,甚至包括危害系统的方式发生故障,被称为拜占庭容错(BFT)。拜占庭理论已经有几十年的历史,但是很大程度上,直到最近像比特币,以太坊这样区块链技术的成功,它的软件实现才得以进一步发展。区块链技术只是以一种现代化的方式对 BFT 的再形式化,而且重点关注 p2p 网络和密码验证。区块链这个名词来源于交易的处理方式,通过区块的批量方式处理交易,每个块包含了前一个块的加密哈希,以此来形成一个链。实际上,区块链数据库真正地优化了 BFT 设计。
Tendermint 包含了两个主要的技术组件:一个区块链共识引擎和一个通用的应用程序接口。共识引擎,叫做 Tendermint Core,保证了每一台机器以相同的顺序记录同一笔交易。应用程序接口,叫做应用程序区块链接口(ABCI),保证了交易可以通过任何一种编程语言进行处理。与其他预先打包内置状态机(比如键值存储或者一个奇怪的脚本语言)的区块链和共识方案不同,开发者可以使用 Tendermint 实现应用的 BFT 状态机复制,而这些应用可以用任何语言编写,而且开发环境对开发者也十分友好。
Tendermint 的设计原则是易使用,易理解,高性能,对于各种分布式应用都十分有用。
1. Tendermint 与其他技术的比较
大体上, Tendermint 与两类软件很类似。第一类包含了分布式的键值存储,比如 Zookeeper,etcd 和 consul,它们都使用了非拜占庭容错共识。第二类就是 “区块链技术”,它既包括了像比特币和以太坊这样的加密货币,也包括了像 Hyperledger Burrow 这样的分布式账本设计。
Zookeeper, etcd, consul
Zookeeper,etcd 和 consul 都是在一个经典的非拜占庭容错共识算法上, 实现了一个键值存储。Zookeeper 使用了 Paxos 一个叫做 Zookeeper Atomic Broadcast 的版本,而 etcd 和 consul 则使用了更年轻,也更简单的 Raft 共识算法。一个典型的集群由 3-5 台机器构成,虽然可以承受 1/2 的机器发生问题,但是只要发生一次拜占庭故障,整个系统就可能被摧毁。它们每一个都提供了一个稍微有别于键值存储的实现,但是都将关注点放在提供分布式系统的基础服务上,比如动态配置,服务发现,锁定,领导人选取等等。
Tendermint 是一个本质上类似的软件,不过有两点关键不同:它是拜占庭容错的,这意味着它可以承受 1/3 机器发生任意形式的故障 – 包括黑客和恶意攻击。
它并不像键值存储,是针对某一指定类型的应用。相反,它关注于任意的状态机复制,因此开发者可以量身打造适合自己的应用逻辑,从键值存储到加密货币到电子投票平台,甚至更多的应用都可适用。
以上内容取自于 consul.io 和 Hashicorp sites.
Bitcoin, Ethereum, etc.
在比特币和以太坊这样的传统加密货币下出现了 Tendermint,它的目的在于提供一个比比特币的工作量证明更加有效和安全的共识算法。在早期,Tendermint 内置了一个简单的货币来参与共识,用户必须向一个保证金账户中“绑定”一定数量的货币,如果他们表现不端,这些钱就会被收回 – 这一点使得 Tendermint 成为一个 POS 算法。
自那时起,Tendermint 就进化为一个能够承载任意应用状态的通用区块链共识引擎。这意味着它可以成为其他区块链软件共识引擎的一个即插即用的替代品。所以基于当前的以太坊代码库,无论是用何种语言, Rust,Go,Haskell,任何人都可以使用 Tendermint 共识运行一个 ABCI 应用。实际上,我们已经完成了这一点(ethermint)。此外,我们也计划为 Bitcoin,ZCash,和其他确定性的应用完成同样的工作。另一个基于 Tendermint 构建的加密货币应用是 Cosmos。
Fabric, Burrow
Fabric 采用了与 Tendermint 类似的方法,但是它更关注对状态的管理,并且要求所有的应用行为能够在多个 docker 容器,叫做 “chaincode” 的模块中运行。它使用了来自 IBM (augmented to handle potentially non-deterministic chaincode) 的 PBFT 实现。通过扩展 Tendermint 来处理未来工作中存在的不确定性,在 Tendermint 中通过一个 ABCI 应用实现这个基于 docker 的行为是完全有可能的。Burrow 是一个以太坊虚拟机和以太坊交易机制的实现,同时附带有名字注册,许可权和天然合约,可替代区块链 API 等额外特性。它使用 Tendermint 作为它的共识引擎,提供一个特殊的应用状态。
2. 什么是 ABCI (应用区块链接口)
区块链应用接口(Application BlockChain Interface,ABCI)允许应用的拜占庭容错复制可以由任意一种编程语言编写。
动机
至今为止,所有的区块链“栈”(比如,比特币)都有着大一统的设计。这就是说,每个区块链栈都是一个单一的程序,这个程序处理了去中心化账本的所有事务。它还包括了 P2P 连接,交易的“内存池”广播,在最新块上的共识,账户余额,图灵完备的合约,用户级别的许可权等。
在计算机科学中,使用大一统的架构,是一个典型的错误实践。这会使得代码重用变得困难,而且如果真的去这么做时,会导致代码库分支的维护变得十分复杂。尤其当代码设计并非模块化时,会产生难以维护的“意大利面条式代码”。
大一统设计的另一个问题是,它限制了区块链栈的语言。比如在以太坊中,它支持一个图灵完备的字节码虚拟机,它限制你必须使用可以编译为那种类型字节码的语言。目前,它所支持的语言是 Serpent 和 Solidity。
相反,我们的方式是从特定区块链应用的应用状态细节中,将共识引擎和 p2p 层分离开来。我们通过将应用细节抽象为一个借口来实现这一点,这个接口被实现为一个 socket 协议。
所以,我们就有了一个接口,应用区块链接口(ABCI),和它的主要实现,Tendermint Socket Protocol (TSP, 或 Teaspoon)。
ABCI 介绍
Tendermint Core (“共识引擎”)通过一个满足 ABCI 标准的 socket 协议与应用进行交流。
举个大家比较熟悉的例子,比特币。比特币是一个加密货币区块链,其中的每个节点维护了一个完全经过审计的 UTXO 数据库。如果有人想要在 ABCI 之上创建一个类似比特币的系统,Tendermint Core 将会负责:
- 在节点间共享区块和交易
- 建立交易(区块链)的标准/不可变顺序
而应用将会负责:
- 维护 UTXO 数据库
- 验证交易的加密签名
- 阻止花费尚未存在的交易
- 允许客户端查询 UTXO 数据库
Tendermint 能够通过在应用过程和共识过程之间,提供一个非常简单的 API (也就是 ABCI)来分解区块链设计。
ABCI 包含了 3 个主要的消息类型,它们由 core 发送至应用,应用会对消息产生相应的回复。
消息的详细说明在这里:ABCI 消息类型。
DeliverTx
消息是应用的主要部分。链中的每笔交易都通过这个消息进行传送。应用需要基于当前状态,应用协议,和交易的加密证书上,去验证接收到 DeliverTx
消息的每笔交易,。一个经过验证的交易然后需要去更新应用状态 – 比如通过将绑定一个值到键值存储,或者通过更新 UTXO 数据库。
CheckTx
消息类似于 DeliverTx
,但是它仅用于验证交易。Tendermint Core 的内存池首先通过 CheckTx
检验一笔交易的有效性,并且只将有效交易中继到其他节点。比如,一个应用可能会检查在交易中不断增长的序列号,如果序列号过时,CheckTx
就会返回一个错误。又或者,他们可能使用一个基于容量的系统,该系统需要对每笔交易重新更新容量。
Commit
消息用于计算当前应用状态的一个加密保证(cryptographic commitment),这个加密保证会被放到下一个区块头。这有一些比较方便的属性。现在,更新状态时的不一致性会被认为是区块链的分支,分支会捕获所有的编程错误。这同样也简化了保障轻节点客户端安全的开发,因为 Merkel-hash 证明可以通过在区块哈希上的检查得到验证,区块链哈希由一个 quorum 签署。
一个应用可能有多个 ABCI socket 连接。Tendermint Core 给应用创建了三个 ABCI 连接:一个用于内存池广播时的交易验证,一个用于运行提交区块时的共识引擎,还有一个用于查询应用状态。
很显然,在创建区块链时,应用的设计者需要非常小心地设计他们的消息处理,这个架构提供一个范例。下图阐释了通过 ABCI 的消息流:
关于确定性的说明
区块链交易处理的逻辑必须是确定性的。如果应用逻辑不确定,就无法在 Tendermint Core 复制节点间达成共识。
在以太坊上的 Solidity 是用于区块链应用一个非常好的语言选择,除了一些其他因素,它还是一个完全确定性的编程语言。但是,通过使用现有的一些语言,比如 Java,C++,Python 和 Go 也是可以创建确定性应用的。对通过避免非确定性来源创建确定性程序,游戏程序员和区块链开发者都已经很熟悉了,比如:
- 随机数生成器(没有确定性的种子)
- 线程上的竞争条件(或者避免多线程)
- 系统时钟
- 未初始化的内存(在像 C 或者 C++ 这样的不安全语言)
- 浮点数算法
- 随机的语言特性(比如 Go 语言的 map 迭代)
尽管程序员可以通过加倍小心来避免非确定性,但是给每个语言创建一个特殊的语法检查器或静态分析器,用它们来检查确定性也是有可能的。在未来,我们可能会与合作者一起创造出这样的工具。
3. 共识概览
Tendermint 是一个易于理解,大部分操作为异步的 BFT 共识协议。下图是一个简单的状态机,它展示了协议遵循的规则:
协议中的参与者叫着 “验证人”(validator)。他们轮流对交易区块进行提议,并对这些区块进行投票。区块会被提交到链上,每一个块占据一个“高度”(height)。提交块可能会失败,如果失败,协议就会开始下一轮的提交,并且一个新的验证人会继续提交那个高度的区块。要想成功提交一个块,需要有两个阶段的投票:“预投票”(pre-vote)和“预提交”(pre-commit)。在同一轮提交中,只有超过 2/3 的验证人对同一个块进行了预提交,这个块才能被提交到链上。
上图右下角有一对夫妇在跳波卡舞,因为验证人做的事情就像是在跳波卡舞。当超过 2/3 的验证人对同一个块进行了预投票,我们就把它叫做一个“波卡”(polka)。每一个预提交都必须被同一轮中的一个波卡所证明。
由于一些原因,验证人可能在提交一个块时失败:当前提议者可能离线了,或者网络非常慢。Tendermint 允许他们证实一个验证人应该被跳过。在进行下一轮的投票前,验证人会等待一小段时间从提议者那里接收一个完整的提议块。这种对于超时的依赖,使得 Tendermint 成为了一个弱同步协议,而非一个异步协议。但是,协议的剩余部分都是异步的,只有在接收到超过 2/3 的验证人集合时,验证人才会采取下一步操作。Tendermint 能够简化的一个原因就是它使用了同样的机制来提交一个块和跳过直接进入下一轮。
基于不到 1/3 的验证人是拜占庭节点的前提,Tendermint 保证了永远都不会违背其安全性 – 也就是说,验证人永远不会在同一高度提交冲突块。为了达到这一点,它引入了一些 “锁定”(locking)的规则,这些规则对流程图中的路径进行了模块化。一旦一个验证人预提交了一个块,它就被“锁定”在了那个块上。然后,
- 它必须为被锁定的那个块进行预投票
- 只有在之后的轮中,有了那个块的一个波卡,它才能够解锁,并为一个新块进行预提交。
权益
在许多系统中,并非所有的验证人都在共识协议有着同样的“高度”(height)。因此,我们对 1/3 还是 2/3 的验证人并不十分感兴趣,而是关心在所有投票力量所占的比例,在个体验证人中,这些比例可能并不是均匀分布的。
由于 Tendermint 可以复制任意的应用程序,定义一种货币,并用该货币来计算投票权力是完全有可能的。当使用货币决定投票权时,这个系统通常叫做权益证明(Proof-of-Stake)系统。通过应用逻辑,可以将验证人的货币持有强制绑定到一个押金账户中。如果他们被发现在共识协议中表现不端,这些钱就会被销毁。这就给协议的安全性增加了一个经济因素,能够让人们量化违反共识假设的成本,这个假设就是只有不到 1/3 的投票权来自拜占庭节点。
Cosmos Network 的设计目的,是在实现了 ABCI 应用的加密货币中使用这个权益证明机制。
⤧ Next post 为什么以太坊不仅仅是一个加密货币 ⤧ Previous post 用表情符号解释比特币 (1)