在以太坊中有两种账户,外部拥有账户(EOA)与合约账户

外部拥有账户

  • 有一个以太币余额
  • 可以发送交易(以太币转账或者激活合约代码)
  • 通过私钥控制
  • 没有相关联的代码

合约账户

  • 有一个以太币余额
  • 有相关联的代码
  • 代码执行是通过交易或者其他合约发送的call来激活
  • 当被执行时
    • 运行在随即复杂度(图灵完备性)
    • 只能操作其拥有的特定存储,例如可以拥有其永久state,
    • 可以call其他合约

所有的以太坊区块链上的行动都是由各账户发送的交易激活。每次一个合约账户收到一个交易,交易自带的参数都会成为代码的输入值运行。合约代码会被以太坊虚拟机(EVM)在每一个参与网络的节点上运行,以作为它们新区块的验证。

交易和消息

交易

"交易"在以太坊中是指一个用来存储消息的签名数据包从一个外部拥有账户发送至另一个账户的过程

这些交易包括:

  • 这个消息的接收者
  • 一个签名,用来证明发送者有意向通过区块链向接收者发送消息
  • 价值域 - 从发送方转移到接受方的wei (ether/10^18) 的数量
  • 一个可选的数据域,用来储存发送给合约的消息
  • 一个GASLIMIT值,代表了这个交易的执行最多被允许使用的计算步骤
  • 一个GASPRICE值,代表了交易发送者愿意支付的gas费用。一个单位的gas表示了执行一个基本指令,例如一个计算步骤

消息

合约具有发送"消息"到其他合约的能力。消息是一个永不串行且只在以太坊执行环境中存在的虚拟对象。他们可以被理解为函数调用。

一个消息包括:

  • 明确的消息发送者
  • 消息的接收者
  • 一个可选的数据域,这是合约实际上的输入数据
  • 一个GASLIMIT值,用来限制这个消息出发的代码执行可用的最大gas数量

一个消息就像一个交易,但是它不是由外部账户生成,而是由合约账户生成。当合约正在执行的代码中运行CALL或者DELEGATECALL这两个命令时,就会生成一个消息。消息有点时候也被成为'内部交易'。与交易类似,一个消息会引导接收的账户运行它的代码。因此,合约账户可以与其他合约账户发生关系。有许多人会误用交易这个词指代消息,所以可能消息这个词已经由于社区的共识而慢慢退出大家的视野,不再被使用。

关于gas

以太坊在区块链上实现了一个运行环境,被称之为以太坊虚拟机(EVM)。每个参与到网络的节点都会运行EVM作为区块验证协议的一部分。它们会验证区块中涵盖的每个交易并在EVM中运行交易所出发的代码。每个网络中的全节点都会进行相同的计算并存储相同的值。合约执行会在所有节点中多次重复,所以使得合约执行的小号极其昂贵,因此也促使了大家将能在链下进行的运算都不放在区块链上进行。对于每个被执行的命令都会由一定的消耗,用单位gas计数。每个合约可以利用的命令都会有一个相应的gas值。

这是一些命令的gas消耗

每笔交易都被要求包括一个gas limit(有时也被称为startGas)和一个交易愿为单位gas支付的费用。矿工可以有选择的打包这些交易并收取这些费用。

在现实中,今天所有的交易最终都是由矿工选择的,用户所选择支付的交易费用多少会影响到该交易被打包所需等待的时长。如果一个交易需要使用的gas数量小于或等于所设置的gas limit,那么这个交易会被处理,如果gas超过了gas limit,那么所有的操作都会被复原,但是交易是成立的,交易费会被矿工收取,区块链会显示这笔交易完成尝试,但因为没有提供足够的gas导致所有合约命令都被复原。因为gas消耗一般只是个估计值,所有许多用户会超额支付gas来保证他们的交易被接受,当交易完成,多余的gas会被以以太币的形式退返给交易发起者。

估算交易消耗

交易费由两部分组成:

  • gasUsed:该交易消耗的总gas量
    • 每个EVM中的命令都被设置了相应的gas消耗量,gasUsed是所有被执行命令的gas消耗值综合
    • 如果希望估算gasUsed,可以使用这个estimateGas的API
  • gasPrice:该交易中单位gas的价格(以以太币计算)
    • 一个用户可以构建和签名一笔交易,但每个用户都可以各自设置自己希望使用的gasPrice,甚至可以是0。
    • 以太坊客户端的Frontier版本有一个默认的gasPrice,即0.05e12 wei
    • 矿工为了最大化他们的收益,如果大量的交易都是使用默认gasPrice即0.05e12 wei,那么基本上就很难又矿工去接受一个低gasPrice交易,更别说0 gasPrice交易了。

交易费 = gasUsed * gasPrice

我们可以将gas limit理解为汽油油箱的上限,gasPrice理解为油价

对于一辆车来说,油价可能是 2.5(价格)每升(单位)。在以太坊中,就是20GWei(价格)每gas(单位)。为了填满你的"油箱",需要10升2.5(价格)每升(单位)。在以太坊中,就是20GWei(价格)每gas(单位)。为了填满你的"油箱",需要10升2.5的油 = $25。同样的,21000个20 GWei的gas = 0.00042 ETH。

因此,总交易费将会是0.00042以太币。

发送代币通常需要消耗大约5万至10万的gas,所以总交易费会上升0.001至0.002个ETH。

区块gas limit

区块gaslimit决定了这个区块能允许的最多gas总理,即能打包多少笔交易。例如,我们有5笔交易的gas limit分别是10、20、30、40和50.如果区块gas limit是100,那么前4笔交易就能被成功打包进入这个区块。矿工有权决定将哪些交易打包入区块。所以,另一个矿工可以选择打包最后两笔交易进入这个区块(50+40),然后再将第一笔交易打包(10)。如果你尝试将一个会使用超过当前区块gas limit的交易打包,这个交易会被网络拒绝,你的以太坊客户端会反馈错误"交易超过区块gas limit"。

目前区块的gas limit是 4,712,357 gas,数据来自于ethstats.net,这表示着大约224笔转账交易(gas limit为21000)可以被塞进一个区块(区块时间大约在15-20秒间波动)。这个协议允许每个区块的矿工调整区块gas limit,任意加减 1/2024(0.0976%)。

区块的gas limit是由在网络上的矿工决定的。与可调整的区块gas limit协议不同的是一个默认的挖矿策略,即大多数客户端默认最小区块gas limit为4,712,388。

以太坊网络上的"DoS"攻击

当以太坊网络上持续地出现全满区块并且有大量交易在网络上待处理时就会出现所谓的DoS情况。同时,矿工有权利根据交易费选择打包哪些交易。如果当时队列中(交易池中)有上千笔交易正在等待打包,那么就有可能造成几个小时的非正常交易延迟。DDoS可能是恶意的也有可能是非恶意的。

恶意的DoS

攻击者通过在他们的智能合约中反复的调用某些命令来让客户端难以处理这些计算,但是这些命令都只消耗少量的gas所以调用起来十分廉价。

这是某次以太坊攻击,矿工被要求降低gas limit到150万,在后来的另一次事件中更改到了200万。也有几次其他的事件要求矿工在网络被攻击时降低区块gas limit。

非恶意的DoS

非恶意的DoS其实就是当网络面临海量交易时需要比平常更多的时间来处理一笔交易。最近由于ICO的流行,以太坊网络多次被交易填满。Infura的朋友们写过一篇与此相关的技术分析文章

为什么区块gas limit在区块被填满时不会自动调整

主要原因是矿工们没有使用gas limit动态调整功能

以太坊协议中存在着让矿工可以通过投票来决定gas limit的机制,所以区块容量不需要经过硬分叉就可以调整。最初,这个机制和另一个默认策略是绑定在一起的,即矿工默认投票使区块gas limit至少有470万,并且趋向于最近1024个区块gas使用量的1.5倍。这使得区块容量会根据需求来自动上升,同时也有一个可用来防御垃圾交易的限制。