以太坊基础
因为大部分 DApp 都是基于以太坊的,所以有必要了解下以太坊的一些技术基础。首先,先来了解下一些基础概念,包括:账户、交易、Gas、区块。
以太坊的账户分两类:外部账户和合约账户。外部账户也称为 EOA,是由用户通过私钥创建的账户,本质上是由一对公私钥所组成,通常由钱包进行管理。而合约账户则是由合约代码创建的,每个具体的智能合约实例就是一个合约账户,合约账户没有私钥。外部账户发起交易时需要用私钥进行签名,而合约账户则无法自己发起交易,通常需要由外部账户调用合约账户的函数来触发合约账户的交易。合约账户内部会存储与之关联的合约代码,如果合约账户收到消息调用,则会执行对应的代码,而外部账户则没有任何关联代码。
以太坊账户的数据结构主要有四个字段:nonce、balance、codeHash、storageRoot。nonce 是每个账户发送的交易数量的计数器,确保每笔交易只处理一次。balance 是该账号所拥有的以太币(Ether)余额,以 Wei 为单位,1 Ether = 10^18 Wei。codeHash 则是该账户所拥有的合约代码哈希,因为外部账户并没有代码,所以外部账号的该字段为空默认值,而合约账户的该字段则不为空,因此也是通过该字段可以判断一个账户是不是合约账户。storageRoot 是该账户存储内容的哈希,外部账户没有存储内容,所以外部账号的该字段也一样是空默认值。
以太坊的交易,本质上就是带有密码学签名的指令,可以是向其他账户转账或调用合约账户的函数。一笔交易只能由外部账户用私钥签名发起,且每笔交易的执行都是一个原子性的事务。交易执行期间,中间环节不管是哪一步发生了错误,整个交易事务都会回滚到执行前的状态。而交易执行成功后,必然会将以太坊账本从一个状态变到了另一个状态。
通常情况下,一笔交易的数据结构主要包括以下字段:from、to、nonce、value、data、gasPrice、gasLimit、v、s、r 等。from 即发起该笔交易的账户地址。to 则是目标地址,如果是转账就是接收代币的地址,如果是调用合约那就是合约地址。nonce 就是账户的发送交易数计数器。value 是由 from 向 to 转移的以太币数量(以 Wei 为单位),如果不需要转移以太币则该值为 0。data 是用于传递交易所需的数据,如果该交易不需要传递数据,则该字段为空。gasPrice 指定该笔交易的燃气价格,gasLimit 用于限制燃气上限,避免交易耗光了以太币。v、s、r 则是该笔交易的签名值,用于验证该笔交易是由 from 账户所签发的。
Gas 即燃气费,是用以太币进行支付的,执行每笔交易时都需要支付燃气费用,会从交易的发起账户中扣除。执行交易需要 gas,是因为占用了矿工的计算资源,所以 gas 作为对矿工打包交易的一种激励。在 2021 年 8 月的以太坊伦敦升级之前,所有 gas 都是奖励给到矿工的。但伦敦升级之后,gas 分为了两部分,基础费和小费,基础费会被直接销毁,而小费才会给到矿工。Gas 价格是由市场供需决定的,这意味着当网络拥堵时,gas 价格会上涨,因为交易需要支付更高的手续费才能被包含在区块中。相反,当网络没有拥堵时,gas 价格会下降。
而多笔交易会被打包进一个区块里提交到区块链上,每个区块主要由两部分组成:区块头和区块体。区块头是区块的元数据,它包含了区块的哈希值、前一个区块的哈希值、时间戳、难度目标和矿工地址等信息。这些元数据可以用于验证区块的有效性,并且可以通过区块头中的哈希值将区块链接在一起形成区块链。而区块体则主要包含了一组交易集合,这些交易是按照一定的顺序排列的,并且交易的执行结果会被记录在状态树中,这个状态树也被称为“世界状态”。
从本质上来说,以太坊就是一个大型的状态机,它的核心原理是:每个区块都代表了一次状态转换,而每次交易都会改变系统的状态。其状态变更如下图所示:
在以太坊中,状态指的是所有账户(包括外部账户和合约账户)的当前状态,包括它们的余额、代码和存储数据等信息。初始状态是一个空状态,没有任何账户。当第一个区块被创建时,它包含了一组初始账户,这些账户构成了初始状态。每当一个新的交易被提交到以太坊网络中时,它会被验证和处理,然后会修改当前状态。交易可以包括向其他账户发送以太币、调用合约的函数、创建新的合约等等操作,这些操作都会对当前状态进行改变。新的状态被写入新的区块中,并广播给整个网络。以太坊这个状态机可以被任何人使用和扩展,通过编写智能合约,用户可以自定义状态转换的规则和条件,从而创建出各种各样的 DApp。
需要注意的是,以太坊中的状态转换是确定性的,也就是说,同样的输入会产生相同的输出。这意味着,每个节点都可以验证交易是否合法,因为它们可以根据输入和当前状态计算出新的状态,并验证新的状态是否与区块中的状态一致。这样可以保证整个网络的安全性和一致性。也因此,以太坊的每笔交易都是需要串行执行的,在一个区块中,所有交易都按照递增的 nonce 值进行排序,这样才能保证状态的一致性。
以太坊的状态机是基于一种称为状态树(state tree)的数据结构实现的。状态树是一个基于 Merkle Tree 的树形结构,它将所有账户的状态保存在一个树结构中,而树的根节点表示整个系统的当前状态。状态树的每个叶子节点都是一个账户的状态,每个节点包含了该账户的地址、余额、代码和存储数据等信息。状态树是一个不可变的数据结构,一旦一个节点被创建,它就不能被修改。如果需要改变账户的状态,就需要创建一个新的节点来代表新的状态。这个特性可以提高以太坊的安全性和可靠性,因为它保证了状态的不可篡改性。在状态转换过程中,交易被应用于当前状态树,并产生一个新的状态树。新的状态树包含了所有账户的新状态。新的状态树被写入新的区块中,并广播给整个网络。每个节点都可以验证新的状态树是否合法,并选择是否接受新的区块。状态树的设计使得以太坊可以高效地处理大量的交易和合约,同时保证了系统的安全性和一致性。如下图所示就是一个简化的世界状态树:
以太坊这个状态机的最终一致性则是通过共识机制达成的。最初,以太坊采用的共识机制是和比特币网络一样的工作量证明(Proof of Work)机制,即 PoW 机制,矿工需要通过大量计算找出符合条件的区块哈希值才能在区块链上出块并获得出块奖励,这个过程也称为挖矿。而从 2022 年 9 月完成以太坊主网与信标链合并之后,完成了从 PoW 过渡到 PoS 机制的转换。PoS 即权益证明机制(Proof of Stake),矿工不再通过大量计算来寻找出符合条件的区块哈希值,而是通过质押以太币进智能合约并运行相应的软件来成为验证者。PoS 机制下的以太坊,用户要想作为验证者参与挖矿,需向存款合约存入 32 个以太币并运行三种独立的软件:执行客户端、共识客户端和验证者。从目前来看,PoS 机制下的以太坊比以往 PoW 机制的能效更高、门槛更低,在经济方面的安全性也更高了。
最后,以太坊网络还分为主网和测试网。主网即主要的以太坊生态区块链,所有具有实际价值的交易都发生在该链的账本中。而测试网顾名思义就是为了测试用的,目前还在使用的有两个测试网,Goerli 和 Sepolia,其中,Goerli 是最被广泛使用的测试网。任何 DApp 智能合约部署到主网之前,都应该先部署到测试网进行充分测试。另外,开发、测试和部署合约时也需要用到测试网的以太币,可以通过测试网的水龙头定期领取固定量的测试币,比如通过 Alchemy 提供的水龙头地址 https://goerlifaucet.com/ 每天可获取 Goerli 网络的 0.02 ETH。