How does Ethereum work, anyway

Ehtereum Yellow Paper

Posted by lanbery on September 10, 2019

区块链的本质:就是一个公共数据库,保存着数字交易的永久记录。 重要的是,这个数据库不需要任何中央机构来维护和保护它

它作为一个不可信的交易系统运行,在这个框架中,个人可以进行点对点交易,而不需要信任第三方或彼此

何为区块链?

区块链是一个具有共享状态的加密安全事务单例机器

  • Cryptographically secure: 加密安全意味着数字货币的创造是由复杂的难以破解的数学算法保证的。
  • Transactional singleton machine : 有一个机器的规范实例负责在系统中创建的所有事务
  • With shared-state :意味着存储在此机器上的状态是共享的,并向所有人开放

以太坊的一些典型特征

The Ethereum blockchain is essentially a transaction-based state machine. In computer science, a state machine refers to something that will read a series of inputs and, based on those inputs, will transition to a new state.

With Ethereum’s state machine, we begin with a “genesis state.” This is analogous to a blank slate, before any transactions have happened on the network. When transactions are executed, this genesis state transitions into some final state. At any point in time, this final state represents the current state of Ethereum.

The state of Ethereum has millions of transactions. These transactions are grouped into “blocks.” A block contains a series of transactions, and each block is chained together with its previous block.

To cause a transition from one state to the next, a transaction must be valid. For a transaction to be considered valid, it must go through a validation process known as mining. Mining is when a group of nodes (i.e. computers) expend their compute resources to create a block of valid transactions.

Any node on the network that declares itself as a miner can attempt to create and validate a block. Lots of miners from around the world try to create and validate blocks at the same time. Each miner provides a mathematical “proof” when submitting a block to the blockchain, and this proof acts as a guarantee: if the proof exists, the block must be valid. For a block to be added to the main blockchain, the miner must prove it faster than any other competitor miner. The process of validating each block by having a miner provide a mathematical proof is known as a “proof of work.”

A miner who validates a new block is rewarded with a certain amount of value for doing this work. What is that value? The Ethereum blockchain uses an intrinsic digital token called “Ether.” Every time a miner proves a block, new Ether tokens are generated and awarded.

分叉解决机制 GHOST protocol

“GHOST” = “Greedy Heaviest Observed Subtree”

Now that you’ve gotten the 10,000-foot overview of what a blockchain is, let’s dive deeper into the main components that the Ethereum system is comprised of:

  • accounts
  • state
  • gas and fees
  • transactions
  • blocks
  • transaction execution
  • mining
  • proof of work

账号(Accounts)

The global “shared-state” of Ethereum is comprised of many small objects (“accounts”) that are able to interact with one another through a message-passing framework. Each account has a state associated with it and a 20-byte address. An address in Ethereum is a 160-bit identifier that is used to identify any account.

  • Externally owned accounts, which are controlled by private keys and have no code associated with them
  • Contract accounts, which are controlled by their contract code and have code associated with them.

Account VS Contract Account

It’s important to understand a fundamental difference between externally owned accounts and contract accounts. An externally owned account can send messages to other externally owned accounts OR to other contract accounts by creating and signing a transaction using its private key. A message between two externally owned accounts is simply a value transfer. But a message from an externally owned account to a contract account activates the contract account’s code, allowing it to perform various actions (e.g. transfer tokens, write to internal storage, mint new tokens, perform some calculation, create new contracts, etc.).

Unlike externally owned accounts, contract accounts can’t initiate new transactions on their own. Instead, contract accounts can only fire transactions in response to other transactions they have received (from an externally owned account or from another contract account). We’ll learn more about contract-to-contract calls in the “Transactions and Messages” section.

Account State

  • nonce : 当账号为wallet账号时,表示该账号发送交易数量,当账号为合约地址时表示创建合约时的nonce数
  • balance : 余额
  • storageRoot : Merkle树根节点数据的hash
  • codeHash : The hash of the EVM (Ethereum Virtual Machine — more on this later) code of this account. For contract accounts, this is the code that gets hashed and stored as the codeHash. For externally owned accounts, the codeHash field is the hash of the empty string

World state

以太坊维护一个全局状态,这个状态有账户和账户状态的映射构成.这些数据存储在称之为Merkle Tree的数据结构中

  • a large number of leaf nodes at the bottom of the tree that contain the underlying data(树的底部包含底层数据的大量叶节点)
  • a set of intermediate nodes, where each node is the hash of its two child nodes(一组中间节点,其中每个节点是其两个子节点的散列)
  • a single root node, also formed from the hash of its two child node, representing the top of the tree (单个根节点,也由其两个子节点的散列组成,代表树的顶部)

he data at the bottom of the tree is generated by splitting the data that we want to store into chunks, then splitting the chunks into buckets, and then taking the hash of each bucket and repeating the same process until the total number of hashes remaining becomes only one: the root hash.

This tree is required to have a key for every value stored inside it. Beginning from the root node of the tree, the key should tell you which child node to follow to get to the corresponding value, which is stored in the leaf nodes. In Ethereum’s case, the key/value mapping for the state tree is between addresses and their associated accounts, including the balance, nonce, codeHash, and storageRoot for each account (where the storageRoot is itself a tree).

This same trie structure is used also to store transactions and receipts. More specifically, every block has a “header” which stores the hash of the root node of three different Merkle trie structures, including:

  • State trie
  • Transactions trie
  • Receipts trie

The ability to store all this information efficiently in Merkle tries is incredibly useful in Ethereum for what we call “light clients” or “light nodes.” Remember that a blockchain is maintained by a bunch of nodes. Broadly speaking, there are two types of nodes: full nodes and light nodes. (在Merkle尝试中有效存储所有这些信息的能力在以太坊中非常有用,我们称之为轻客户机或轻节点。记住区块链是由一堆节点维护的。一般来说,节点有两种类型:全节点和轻节点。)

A full archive node synchronizes the blockchain by downloading the full chain, from the genesis block to the current head block, executing all of the transactions contained within. Typically, miners store the full archive node, because they are required to do so for the mining process. It is also possible to download a full node without executing every transaction. Regardless, any full node contains the entire chain. 全节点通过同步区块链来下载完整区块链信息,全节点将从创世区块到当前 头块数据.通常矿机需要同步链上全部数据不存储,因为这是挖矿过程所必需的.

But unless a node needs to execute every transaction or easily query historical data, there’s really no need to store the entire chain. This is where the concept of a light node comes in. Instead of downloading and storing the full chain and executing all of the transactions, light nodes download only the chain of headers, from the genesis block to the current head, without executing any transactions or retrieving any associated state. Because light nodes have access to block headers, which contain hashes of three tries, they can still easily generate and receive verifiable answers about transactions, events, balances, etc. (轻节点不是下载和存储完整链并执行所有交易,而是仅下载头链,从创世块到当前头,不执行任何交易或 检索任何关联的状态。 由于轻节点可以访问包含三次尝试的哈希值的区块头,因此它们仍然可以轻松生成和接收有关交易、事件、余额等的可验证答案)

The reason this works is because hashes in the Merkle tree propagate upward — if a malicious user attempts to swap a fake transaction into the bottom of a Merkle tree, this change will cause a change in the hash of the node above, which will change the hash of the node above that, and so on, until it eventually changes the root of the tree.

Any node that wants to verify a piece of data can use something called a “Merkle proof” to do so. A Merkle proof consists of: A chunk of data to be verified and its hash The root hash of the tree The “branch” (all of the partner hashes going up along the path from the chunk to the root)

Gas and payment

以太坊中一个非常重要的概念是费用的概念。以太坊网络上交易的每一个计算都会产生费用,没有免费的午餐!这笔费用是以Gas的名义支付的。

记住,GasLimit代表的是发送者愿意花钱的最大gas number。如果他们的账户余额中有足够的以太币来支付这个最大值,他们就可以开始了。在交易结束时,以原来的价格兑换任何未使用的gas,寄件人将得到退款。

如果发送方没有提供执行交易所需的gas,交易就会“耗尽gas”并被视为无效。 在这种情况下,交易处理中止并且发生的任何状态变化都被逆转,因此我们最终回到交易之前的以太坊状态。 此外,还会记录交易失败的记录,显示尝试进行的交易以及失败的位置。 并且由于机器在用完 gas 之前已经花费了精力来运行计算,因此从逻辑上讲,没有任何 gas 退还给发送者

通常,发送方愿意支付的 gas 价格越高,矿工从交易中获得的价值就越大。 因此,矿工更有可能选择它。 通过这种方式,矿工可以自由选择他们想要验证或忽略哪些交易。 为了指导发送者设定什么 gas 价格,矿工可以选择广告他们将执行交易的最低 gas 价格

What’s the purpose of fees

以太坊工作方式的一个重要方面是网络执行的每一个操作都同时受到每个完整节点的影响。 然而,以太坊虚拟机上的计算步骤非常昂贵。 因此,以太坊智能合约最适合用于简单的任务,例如运行简单的业务逻辑或验证签名和其他加密对象,而不是更复杂的用途,例如文件存储、电子邮件或机器学习,这会给网络带来压力。 征收费用可以防止用户对网络造成负担

交易和消息

从最基本的意义上讲,交易是一条经过加密签名的指令,由外部拥有的帐户生成,序列化,然后提交到区块链。

所有交易都包含以下组件,无论其类型如何:

  • nonce: 发送者发送的交易数量的计数
  • gasPrice: 发送方愿意为执行交易所需的每单位 gas 支付的 Wei 数量
  • gasLimit: 发送方愿意为执行此交易支付的最大 gas 量。 在任何计算完成之前,此金额是预先设定和支付的
  • to: 收件人的地址。 在创建合约的交易中,合约账户地址尚不存在,因此使用空值
  • value: 要从发送方转移到接收方的 Wei 数量。 在创建合约的交易中,此值用作新创建的合约账户中的起始余额
  • v, r, s: used to generate the signature that identifies the sender of the transaction
  • init : 用于初始化新合约账户的 EVM 代码片段。 init 只运行一次,然后被丢弃。 当 init 首次运行时,它返回账户代码的主体,这是与合约账户永久关联的一段代码
  • data : 消息调用的输入数据(即参数)。 例如,如果智能合约用作域注册服务,则对该合约的调用可能需要输入字段,例如域和 IP 地址

存在于以太坊状态全局范围内的合约可以与同一范围内的其他合约进行对话。 他们这样做的方式是通过与其他合约的“消息”或“内部交易”。 我们可以将消息或内部交易视为类似于交易,主要区别在于它们不是由外部拥有的帐户生成的。 相反,它们是由合约生成的。 它们是虚拟对象,与交易不同,它们没有序列化,仅存在于以太坊执行环境中。

需要注意的一件重要事情是内部交易或消息不包含 gasLimit。 这是因为 gas 限制是由原始交易的外部创建者(即一些外部拥有的帐户)决定的。 外部拥有的账户设置的 gas 限制必须足够高以执行交易,包括由于该交易而发生的任何子执行,例如合约到合约的消息。 如果在交易和消息链中,特定消息的执行耗尽了 gas,那么该消息的执行以及由执行触发的任何后续消息都将恢复。 但是,父执行不需要恢复。

Blocks (数据块)

All transactions are grouped together into “blocks.” A blockchain contains a series of such blocks that are chained together.

  • the block header
  • nformation about the set of transactions included in that block
  • a set of other block headers for the current block’s ommers

Block header

  • parentHash: a hash of the parent block’s header (this is what makes the block set a “chain”)
  • ommersHash: a hash of the current block’s list of ommers
  • beneficiary: the account address that receives the fees for mining this block
  • stateRoot : the hash of the root node of the state trie (recall how we learned that the state trie is stored in the header and makes it easy for light clients to verify anything about the state)
  • transactionsRoot: the hash of the root node of the trie that contains all transactions listed in this block
  • receiptsRoot: the hash of the root node of the trie that contains the receipts of all transactions listed in this block
  • logsBloom: a Bloom filter (data structure) that consists of log information
  • difficulty : the difficulty level of this block
  • number [又叫区块高度]: the count of current block (the genesis block has a block number of zero; the block number increases by 1 for each each subsequent block)
  • gasLimit: the current gas limit per block
  • gasUsed : the sum of the total gas used by transactions in this block
  • timestamp : the unix timestamp of this block’s inception
  • extraData: extra data related to this block
  • mixHash: a hash that, when combined with the nonce, proves that this block has carried out enough computation
  • nonce : a hash that, when combined with the mixHash, proves that this block has carried out enough computation

注意 : 每个区块都包含一下三种MerkleTree 结构的数据

  • state (stateRoot)
  • transactions (transactionsRoot)
  • receipts (receiptsRoot)

Logs 日志

以太坊允许使用日志来跟踪各种交易和消息。 合约可以通过定义它想要记录的“事件”来显式地生成日志

以太坊日结构

  • account address
  • a series of topics that represent various events carried out by this transaction
  • any data associated with these events (如合约中定义的Event )

Bloom filter: 一种空间效率高的概率数据结构

Transaction receipt 交易凭证

  • the block number
  • block hash
  • transaction hash
  • cumulative gas used in the current block after the current transaction has executed
  • logs created when executing the current transaction
  • status and so on

Block difficulty

The “difficulty” of a block is used to enforce consistency in the time it takes to validate blocks. The genesis block has a difficulty of 131,072, and a special formula is used to calculate the difficulty of every block thereafter. If a certain block is validated more quickly than the previous block, the Ethereum protocol increases that block’s difficulty.

区块的“难度”用于在验证块所需的时间内强制执行一致性。 创世区块的难度为131,072,之后的每个区块的难度都用特殊的公式计算。 如果某个区块的验证速度比前一个区块更快,则以太坊协议会增加该区块的难度。

区块的难度会影响 nonce,它是在挖掘区块时必须计算的哈希,使用工作量证明算法

Transaction Execution (以太坊最复杂的部分)

假设您将交易发送到以太坊网络进行处理。 将以太坊的状态转换为包括您的交易会发生什么?

首先,所有交易必须满足一组初始要求才能执行,如下条件:

  • 交易必须是格式正确的 RLP。 “RLP”代表“递归长度前缀”,是一种用于编码二进制数据嵌套数组的数据格式。 RLP 是以太坊用于序列化对象的格式。
  • 有效的交易签名
  • 有效的交易随机数。 帐户的随机数是从该帐户发送的交易计数。 要有效,交易随机数必须等于发件人帐户的随机数。
  • Gaslimit : 这个数据必须大于等于交易所需gas number
    • 执行交易的预定义成本为21,000 gas
    • 与交易一起发送的数据的 gas 费(每字节数据或代码等于 0 时为4 gas,每个非零字节数据或代码 为68 gas)
    • 如果交易是创建合约的交易,额外的 32,000 gas

  • 发送者的账户余额必须有足够的以太币来支付发件人必须支付的“前期”gas费用。

如果交易满足上述所有有效性要求,那么我们进入下一步:

首先,我们从发送方的余额中扣除执行的前期成本,并将发送方账户的 nonce 增加 1 以计算当前交易。 此时,我们可以计算剩余的gas为交易的总gas限制减去使用的固有gas

接下来,事务开始执行。在整个交易执行过程中,以太坊跟踪子状态。这个子状态是一种记录交易过程中积累的信息的方法,这些信息在交易完成后将立即被需要。具体地说,它包含

  • Self-destruct set:(a set of accounts (if any) that will be discarded after the transaction completes) 交易完成后将被丢弃的一组账户
  • Log series: archived and indexable checkpoints of the virtual machine’s code execution. (虚拟机代码执行的存档和可索引检查点)
  • Refund balance: the amount to be refunded to the sender account after the transaction. Remember how we mentioned that storage in Ethereum costs money, and that a sender is refunded for clearing up storage? Ethereum keeps track of this using a refund counter. The refund counter starts at zero and increments every time the contract deletes something in storage (交易后要退还到发送者帐户的金额。 还记得我们是如何提到以太坊中的存储需要花钱,而发件人因清理存储而获得退款的吗? 以太坊使用退款柜台跟踪这一点。 退款计数器从零开始并在每次合约删除存储中的内容时递增)

接下来,处理交易(Transaction)所需的各种计算。

一旦交易所需的所有步骤都处理完毕,并且假设没有无效状态,则通过确定要退还给发送方的未使用Gas来最终确定状态。 除了未使用的gas之外,发送者还从我们上面描述的“退款余额”中退还了一些津贴

Once the sender is refunded

  • the Ether for the gas is given to the miner
  • the gas used by the transaction is added to the block gas counter (which keeps track of the total gas used by all transactions in the block, and is useful when validating a block)
  • all accounts in the self-destruct set (if any) are deleted (删除自毁组中的所有帐户,如果存在)

最后,剩下的是由事务创建的新状态和一组日志。

Contract creation 合约创建

当交易是“创建合约”时,其实是交易的目的是创建一个新的合约账户(即在以太坊上创建合约账户)

创建合约需要先使用一个特殊的公式声明新帐户的地址

  • Setting the nonce to zero
  • If the sender sent some amount of Ether as value with the transaction, setting the account balance to that value
  • Deducting the value added to this new account’s balance from the sender’s balance
  • Setting the storage as empty
  • Setting the contract’s codeHash as the hash of an empty string

一旦我们初始化了账户,我们就可以实际创建账户,使用随交易发送的 init 代码。 在这个 init 代码的执行过程中发生的事情是多种多样的。 根据合约的构造函数,它可能会更新账户的存储、创建其他合约账户、进行其他消息调用等

在执行初始化合约的代码时,它使用了gas。 交易消耗的gas不能超过剩余的gas。 如果是,则执行将遇到气体耗尽 (OOG) 异常并退出。 如果交易由于气体耗尽异常退出,则状态将恢复到交易前的时刻。 发件人不会退还在用完之前花费的gas

但是,如果发送方在交易中发送了任何 Ether 值,则即使合约创建失败,Ether 值也会被退还

Message calls 消息调用

消息调用的执行类似于合约创建的执行,但有一些不同。

在以太坊的最新更新之前,没有办法在不让系统消耗您提供的所有Gas的情况下停止或恢复交易的执行。 例如,假设您编写了一个合约,当调用者无权执行某些交易时,该合约会引发错误。 在以前的以太坊版本中,剩余的 gas 仍然会被消耗掉,并且不会将任何 gas 退还给发送者。 但是拜占庭更新包括一个新的“恢复”代码,允许合约停止执行并恢复状态更改,而不消耗剩余的气体,并且能够返回失败交易的原因。 如果交易因还原而退出,则未使用的 gas 将返还给发送者。

Execution model

接下来,我们将看看Transaction是如何在 VM 中实际执行的

EVM 是一个图灵完备的虚拟机。 EVM 具有典型图灵整机没有的唯一限制是 EVM 本质上受gas约束。 因此,可以完成的总计算量本质上受到所提供的gas number的限制

此外,EVM 具有基于堆栈的架构。 堆栈机是使用后进先出堆栈来保存临时值的计算机。

EVM中每个堆栈项的大小为256位,堆栈的最大大小为1024

EVM 具有内存,其中项目存储为字寻址的字节数组。 内存是易失性的,这意味着它不是永久性的

EVM 还具有存储功能。 与内存不同,存储是非易失性的,并作为系统状态的一部分进行维护。 EVM 将程序代码单独存储在只能通过特殊指令访问的虚拟 ROM 中。 通过这种方式,EVM 不同于典型的冯诺依曼架构,其中程序代码存储在内存或存储中

EVM也有自己的语言:EVM字节码。当像你我这样的程序员编写在以太坊上运行的智能合约时,我们通常用更高级别的语言编写代码,比如solid。然后我们可以将其编译为EVM能够理解的EVM字节码

Mining proof of work (工作量挖矿)

区块 部分简要介绍了块难度的概念。 赋予区块难度意义的算法称为工作量证明 (PoW)。

  • 其中 m 是 mixHash,n 是 nonce,Hn 是新块的头(不包括必须计算的 nonce 和 mixHash 组件),Hn 是块头的 nonce,d 是 DAG,这是一个 大数据集。

PoW 的工作模式

  • 为每个块计算一个“种子”。 每个“时期”的种子都不同,其中每个时期的长度为 30,000 个区块。 对于第一个纪元,种子是一系列 32 个字节的零的散列。 对于每个后续时期,它是前一个种子哈希的哈希。 使用此种子,节点可以计算伪随机“缓存”
  • 这个缓存非常有用,因为它支持“轻节点”的概念,我们之前在这篇文章中讨论过。 轻节点的目的是为某些节点提供有效验证交易的能力,而无需存储整个区块链数据集。 轻节点可以仅基于此缓存来验证交易的有效性,因为缓存可以重新生成它需要验证的特定块。
  • 使用缓存,节点可以生成 DAG“数据集”,其中数据集中的每个项目都依赖于从缓存中伪随机选择的少量项目。 为了成为一名矿工,你必须生成这个完整的数据集; 所有完整的客户和矿工都存储这个数据集,并且数据集随着时间线性增长
  • 然后,矿工可以随机抽取数据集,并通过数学函数将它们散列在一起,形成“mixHash”。 矿工将重复生成 mixHash,直到输出低于所需的目标随机数。 当输出满足此要求时,该随机数被认为是有效的,并且可以将块添加到链中

Mining as a security mechanism (挖矿作为一种安全机制)

总体而言,PoW 的目的是以加密安全的方式证明已经花费了特定数量的计算来生成一些输出(即随机数)。 这是因为除了枚举所有可能性之外,没有更好的方法来找到低于所需阈值的随机数。 重复应用哈希函数的输出具有均匀分布,因此我们可以确定,平均而言,找到这样一个随机数所需的时间取决于难度阈值。 难度越高,解决 nonce 所需的时间就越长。 通过这种方式,PoW 算法赋予了难度的概念,用于加强区块链的安全性。

这正是 PoW 算法所做的:它确保特定区块链在未来仍然是规范的,这使得攻击者很难创建覆盖历史特定部分的新块(例如,通过擦除交易或创建虚假交易) 或维护一个叉子。 为了首先验证他们的区块,攻击者需要始终比网络中的任何其他人更快地解决随机数,以便网络相信他们的链是最重的链(基于我们之前提到的 GHOST 协议的原则)。 除非攻击者拥有超过一半的网络挖矿算力,否则这是不可能的,这种情况称为多数 51% 攻击。

Mining as a wealth distribution mechanism (挖矿作为一种财富分配机制)

除了提供安全的区块链之外,PoW 也是一种将财富分配给那些为提供这种安全性而花费计算的人的方式。 回想一下,矿工因开采一个区块而获得奖励,包括:

  • 获得出块权力的静态区块奖励为 5 以太(现在已更改为 3 以太)
  • 区块中包含的交易在区块内消耗的gas成本
  • 将 ommers 作为区块的一部分的额外奖励

为了确保使用 PoW 共识机制进行安全和财富分配的长期可持续性,以太坊努力灌输这两个属性

  • 让尽可能多的人可以访问它。 换句话说,人们不应该需要专门的或不常见的硬件来运行算法。 这样做的目的是使财富分配模型尽可能开放,以便任何人都可以提供任意数量的计算能力来换取 Ether
  • 减少任何单个节点(或小集)赚取不成比例利润的可能性。 任何可以赚取不成比例利润的节点都意味着该节点对确定规范区块链有很大的影响。 这很麻烦,因为它降低了网络安全性

在比特币区块链网络中,与上述两个属性相关的一个问题是 PoW 算法是一个 SHA256 哈希函数。 这类函数的弱点是使用专用硬件(也称为 ASIC)可以更有效地解决它

为了缓解这个问题,以太坊选择使其 PoW 算法(Ethhash)顺序内存困难。 这意味着该算法经过精心设计,因此计算随机数需要大量内存和带宽。 大内存要求使得计算机难以并行使用其内存同时发现多个随机数,而高带宽要求使得即使是超快的计算机也难以同时发现多个随机数。 这降低了中心化的风险,并为进行验证的节点创造了一个更公平的竞争环境。

需要注意的一件事是,以太坊正在从 PoW 共识机制过渡到一种称为“PoS”的机制。 (ETH 2.0)