您的位置:首页?区块链?正文

以太坊是如何运作的?(一)

介绍

不管你是否了解它究竟是什么, 也许你已经听说过以太坊区块链。 因为它在新闻中经常出现。 假如你对以太坊没有基本了解, 阅读本文可能有点摸不着头脑。 那以太坊到底是什么?它本质上是公共数据库, 它保存数字交易的永久记录。 重要的是,

这个数据库并不要求任何中心机构来维持和保护它的安全。 相反, 它作为一个“去中介信任”的交易系统进行运作, 这是一种框架, 在其中个人可以进行对等交易, 同时无需任何第三方或彼此之间的信任。

还感到困惑吗?这就是本文可以发挥作用的地方。 我的目标是从技术层面来解释以太坊是如何运作的, 这里不会有复杂的数学或吓人的公式。 即使你不是程序员, 我也希望你至少能有所收获。 如果有部分太过于技术化和太过于晦涩, 这也没有关系。 你不需要懂得所有细节。 我建议只需从大的层面去理解它。

本文中提到的主题都是以太坊黄皮书中的概念剖析。 我添加了自己的解释和图表, 这样更容易理解。 如果你对技术挑战感兴趣, 也可直接阅读黄皮书。

区块链的定义

区块链是一种“具有共享状态的加密安全的交易单例机。 ”让我们拆解一下。

“加密安全”是指所创建的数字货币由复杂的数学算法来保证它的安全, 这个算法很难被破解。 想一下各种防火墙。 他们几乎不可能欺骗系统, 例如创造虚假交易、删除交易记录等。

“交易的单例机”是指有单个规范实例机负责所有在系统中创建的交易。 换句话说, 这里有一个所有人都相信的单一全球事实。

“具有共享状态”是指存储在这个机器上的状态是共享的, 向每个人公开。

以太坊实现的是这种区块链的范式。

以太坊区块链的范式阐述

以太坊区块链本质上是基于交易的状态机。 在计算机科学中, 状态机指的是读取一系列的输入的东西, 基于这些输入, 会转换到新的状态。

有了以太坊的状态机, 我们从“创世状态”开始。 这类似于空白平板, 没有任何交易在网络上发生过。 当交易执行, 创世状态转换为某种最终状态。 在任何时间点,

最终状态代表以太坊的当前状态。

以太坊的状态有数百万的交易。 这些交易组成区块。 一个区块包含一系列的交易, 并且每个区块与其前一个区块链接在一起。

要让一个状态转换到下一个状态, 交易必须是有效的。 一个交易要被认可为有效, 必须经过验证的过程, 这个过程称之为挖矿。 一群节点(计算机)花费它们的计算资源来创建包含有效交易的区块, 这就是挖矿。

网络上的任何节点都可以声明自己是矿工节点, 都可以试图创建和验证区块。 全世界有很多矿工试图在同一时间创建和验证区块。 当向区块链提交区块时, 每个矿工都会提供一个数学“证明”, 该证明作为一个保证:如果证明存在, 区块必须有效。

对于要添入主链的区块, 矿工必须比其他竞争对手更快地证明。 通过让矿工提供数学证明的方法来验证每个区块的过程也就是所谓的“工作量证明”。

验证新区块的矿工会被奖励一定数量的价值, 以激励他们完成此项工作。 什么样的价值?以太坊区块链使用原生数字代币“Ether”。 每次矿工证明了一个区块, 新的Ether代币就会产生并给予矿工奖励。

你可能会想:用什么来保证大家都在同一条链上?我们怎么能肯定不会存在一部分矿工决定创建自己的链?

在上文也提到, 我们把区块链定义为一个具有共享状态的交易单例机。 使用此定义, 我们可以理解, 正确的当前状态是一个单一的全球事实, 每个人都必须接受。 如有多种状态(或多条链)会毁掉整个系统, 因为它不可能就哪个状态才是正确状态方面达成一致。 如果链有多条, 你可能在一条链上有10个代币, 另外一条上有20个代币, 还有一条上有40个代币。 在这种情况下, 无法确定那条链是最“有效”的。

不管什么时候, 只要有多条路径,

就会产生“分叉”。 我们通常希望避免分叉, 因为它们会破坏系统并强迫人们选择相信那一条链。

为了决定那条路径是最有效的, 并且防止多条链产生, 以太坊使用称为“GHOST协议”的机制。 “GHOST”=“Greedy Heaviest Observed Subtree”

简单来说, GHOST协议说我们必须挑选耗费最多算力的那条路径。 决定那条路径的一个方法是使用最新区块的区块编号(“叶区块”), 它表示当前该路径的全部区块总数(不包括创世区块)。 区块编号越高, 路径就越长, 抵达“叶区块”所需的挖矿工作量就越大。 使用这种推理方法, 我们能够就当前状态的规范版本达成一致。

现在你已经多少了解一些区块链的大概, 让我们更加深入了解以太坊系统的主要组件:

l?账户

l?状态

l?gas和费用

l?交易

l?区块

l?交易执行

l?挖矿

l?PoW

开始前要注意一个事情:本文说的X的“哈希”时, 通常是指以太坊使用的KECCAK-256哈希。

账户

以太坊的全球“共享状态”是由很多小的对象(账户)组成, 这些账户通过消息传递框架实现彼此交互。每个账户都有一个与之关联的状态以及一个20字节的地址。以太坊中的地址是160位比特的标识符,用于标识任何账户。

有两种类型的账户:

l?外部账户,由私钥控制,没有与之关联的代码。

l?合约账户,由合约代码控制,有与之关联的代码。

外部账户Vs.合约账户

理解外部账户和合约账户之间的根本区别是非常重要的。通过创建及使用其私钥签名一个交易,外部账户能够给其他外部账户或其他合约账户发送消息。两个外部账户之间的消息只是简单的价值传输。但从外部账户发送到合约账户的消息可以激活合约账户的代码,允许它执行各种操作(例如,转移代币、写入内部存储、发新币、执行计算、创建新合约等。)

与外部账户不同,合约账户无法自行启动新的交易。相反,合约账户仅能够通过响应其他它们收到的交易来触发自身的交易。比如从外部账户或从其他的合约账户的交易来触发。我们会在“交易和消息”章节中了解到更多合约到合约的请求。

因此,任何以太坊区块链上发生的操作始终由外部账户所触发的交易来启动。

账户状态

账户状态由四个部分组成,无论账户类型是什么,它们都存在:

Nonce:如果该账户是外部账户,这个数代表从这个账户地址发出来的交易数。如果该账户是合约账户,则该nonce是该账户创建的合约数。

余额:该地址拥有的Wei数。每个Ether有1e+18Wei。

StorageRoot:Merkle Patricia树的根节点的哈希值(后续会解释Merkle tree)。Merkle tree对该账户的存储内容的哈希进行编码,默认情况下为空。

CodeHash:该账户EVM代码的哈希。对合约账户而言,这是被哈希后并存储为CodeHash的代码。对于外部账户而言,codehash字段是空字符串的哈希。

世界状态

我们知道以太坊的全球状态包括账户地址和账户状态之间的映射。该映射存储在Merkle Patricia tree树的数据结构中。

Merkle树是一种由一组节点组成的二叉树,其中:

l?树底部的大量叶节点包含底层数据

l?一组中间节点,其中每个节点都是两个子节点的哈希

l?一个根节点,也是由两个子节点的哈希形成,表示树的顶部

树底部的数据是通过拆分数据产生,这些数据我们希望存储进入块中,然后把块拆分进入桶中,之后取每个桶的哈希并重复相同的过程,直到剩余的哈希总数变为只有一个:根哈希。

Merkle树要求每个存储其中的值都有一个键。从树的根节点开始,键应该告诉你要遵循哪个子节点,以获取相应的值,值是存储在叶节点上的。在以太坊的案例中,状态树的键/值映射是在地址和它们相关的账户之间的,包括了每个账户的余额、nonce、codeHash、StorageRoot(其中StorageRoot本身就是一颗树)。

(来源:以太坊白皮书)

相同的trie结构也被用于存储交易和收据。更具体来说,每个区块都有一个“块头”,块头存储三种不同Merkle trie结构的根节点哈希,包括:

l?状态trie

l?交易trie

l?收据trie

把所有这些信息有效地存入Merkle tries的能力在以太坊中非常有用,因为我们有“轻客户端”和“轻节点”。请记住,区块链由一堆节点维护。广义上讲,有两类节点:全节点和轻节点。

完整节点通过下载整个链数据来同步区块链,从创世区块到当前区块,执行其中包含的所有交易。通常,矿工存储完整到归档节点,因为它们要去挖矿必须执行该操作。无须执行任一操作也可以下载完整节点。无论如何,任何全节点包括所有链。

但,除非一个节点有必要执行每个交易或为方便查询历史数据,否则,没有必要存储整条链的数据。这也是轻节点概念的由来。无须下载和存储完整链的数据以及执行所有交易,轻节点仅下载链头,从创世区块到当前区块的块头,而无须执行任何交易或检索任何相关的状态。由于轻节点可以访问区块头,区块头包含了三种tries的哈希,它们依然能够轻易生成和接收可验证的答案,如关于交易、事件、余额等。

这样做能行的原因是Merkle树中的哈希是向上传播的——如果一个恶意用户试图把虚假交易置入Merkle树的底部,这样的改变会导致上面节点的哈希发生变化,然后会继续改变上面节点的哈希,如此传递下去,最终改变了树根的哈希。

想要验证数据的任何节点都能使用“Merkle证明”来达成目的。Merkle证明包含:

l?要证明的一堆数据和它的哈希

l?树的根哈希

l?“分支”(所有伙伴哈希从块到根的路径顺延而上)

所有读取证明的人都能验证分支的哈希是沿着树向上一致的,因此,给定的区块实际上是在树中的某个位置上。

总之,使用Merkle Patricia树的好处是该结构的根节点在加密方面依赖于存储在树上的数据,因此根节点哈希能够用于该数据的安全标识。既然区块头包含状态、交易以及收据树三者的根哈希,因此,任何节点都可以验证一小部分的以太坊状态,而无需存储所有状态,完整节点可能会非常大。

--未完待续---

这些账户通过消息传递框架实现彼此交互。每个账户都有一个与之关联的状态以及一个20字节的地址。以太坊中的地址是160位比特的标识符,用于标识任何账户。

有两种类型的账户:

l?外部账户,由私钥控制,没有与之关联的代码。

l?合约账户,由合约代码控制,有与之关联的代码。

外部账户Vs.合约账户

理解外部账户和合约账户之间的根本区别是非常重要的。通过创建及使用其私钥签名一个交易,外部账户能够给其他外部账户或其他合约账户发送消息。两个外部账户之间的消息只是简单的价值传输。但从外部账户发送到合约账户的消息可以激活合约账户的代码,允许它执行各种操作(例如,转移代币、写入内部存储、发新币、执行计算、创建新合约等。)

与外部账户不同,合约账户无法自行启动新的交易。相反,合约账户仅能够通过响应其他它们收到的交易来触发自身的交易。比如从外部账户或从其他的合约账户的交易来触发。我们会在“交易和消息”章节中了解到更多合约到合约的请求。

因此,任何以太坊区块链上发生的操作始终由外部账户所触发的交易来启动。

账户状态

账户状态由四个部分组成,无论账户类型是什么,它们都存在:

Nonce:如果该账户是外部账户,这个数代表从这个账户地址发出来的交易数。如果该账户是合约账户,则该nonce是该账户创建的合约数。

余额:该地址拥有的Wei数。每个Ether有1e+18Wei。

StorageRoot:Merkle Patricia树的根节点的哈希值(后续会解释Merkle tree)。Merkle tree对该账户的存储内容的哈希进行编码,默认情况下为空。

CodeHash:该账户EVM代码的哈希。对合约账户而言,这是被哈希后并存储为CodeHash的代码。对于外部账户而言,codehash字段是空字符串的哈希。

世界状态

我们知道以太坊的全球状态包括账户地址和账户状态之间的映射。该映射存储在Merkle Patricia tree树的数据结构中。

Merkle树是一种由一组节点组成的二叉树,其中:

l?树底部的大量叶节点包含底层数据

l?一组中间节点,其中每个节点都是两个子节点的哈希

l?一个根节点,也是由两个子节点的哈希形成,表示树的顶部

树底部的数据是通过拆分数据产生,这些数据我们希望存储进入块中,然后把块拆分进入桶中,之后取每个桶的哈希并重复相同的过程,直到剩余的哈希总数变为只有一个:根哈希。

Merkle树要求每个存储其中的值都有一个键。从树的根节点开始,键应该告诉你要遵循哪个子节点,以获取相应的值,值是存储在叶节点上的。在以太坊的案例中,状态树的键/值映射是在地址和它们相关的账户之间的,包括了每个账户的余额、nonce、codeHash、StorageRoot(其中StorageRoot本身就是一颗树)。

(来源:以太坊白皮书)

相同的trie结构也被用于存储交易和收据。更具体来说,每个区块都有一个“块头”,块头存储三种不同Merkle trie结构的根节点哈希,包括:

l?状态trie

l?交易trie

l?收据trie

把所有这些信息有效地存入Merkle tries的能力在以太坊中非常有用,因为我们有“轻客户端”和“轻节点”。请记住,区块链由一堆节点维护。广义上讲,有两类节点:全节点和轻节点。

完整节点通过下载整个链数据来同步区块链,从创世区块到当前区块,执行其中包含的所有交易。通常,矿工存储完整到归档节点,因为它们要去挖矿必须执行该操作。无须执行任一操作也可以下载完整节点。无论如何,任何全节点包括所有链。

但,除非一个节点有必要执行每个交易或为方便查询历史数据,否则,没有必要存储整条链的数据。这也是轻节点概念的由来。无须下载和存储完整链的数据以及执行所有交易,轻节点仅下载链头,从创世区块到当前区块的块头,而无须执行任何交易或检索任何相关的状态。由于轻节点可以访问区块头,区块头包含了三种tries的哈希,它们依然能够轻易生成和接收可验证的答案,如关于交易、事件、余额等。

这样做能行的原因是Merkle树中的哈希是向上传播的——如果一个恶意用户试图把虚假交易置入Merkle树的底部,这样的改变会导致上面节点的哈希发生变化,然后会继续改变上面节点的哈希,如此传递下去,最终改变了树根的哈希。

想要验证数据的任何节点都能使用“Merkle证明”来达成目的。Merkle证明包含:

l?要证明的一堆数据和它的哈希

l?树的根哈希

l?“分支”(所有伙伴哈希从块到根的路径顺延而上)

所有读取证明的人都能验证分支的哈希是沿着树向上一致的,因此,给定的区块实际上是在树中的某个位置上。

总之,使用Merkle Patricia树的好处是该结构的根节点在加密方面依赖于存储在树上的数据,因此根节点哈希能够用于该数据的安全标识。既然区块头包含状态、交易以及收据树三者的根哈希,因此,任何节点都可以验证一小部分的以太坊状态,而无需存储所有状态,完整节点可能会非常大。

--未完待续---