以太坊上新的事务类型:EIP-2718 简介
以太坊采用不同的事务类型来定义不同的操作,例如,将以太币发送至某个地址、部署合约等等。
在最近的柏林升级之前,以太坊主要有 4 种不同的事务 “类型”:
-
带有收款方地址、数据字段的常规事务
-
不带有收款方地址的合约部署事务,其数据字段填写的是合约代码
-
签名
v
值不含链 ID 的事务(EIP155 实行之前) -
签名
v
值含有链 ID 的事务
上述事务类型都采用相同的格式。不同的以太坊客户端、库和其它工具必须分析每个事务来判断它属于哪个类型。这四种不同的事务类型引入了很多复杂的情况。我们需要查看事务的所有字段来判断其所属类型。这是人们在提议新的事务类型(如元事务、多签事务等)时不得不面对的重大难题,直到 EIP 2718 出现才打破这一困境。
以太坊现在有了新的事务标准 Typed Transaction Envelope(类型化事务封套),由 EIP 2718 的提议者 Micah Zoltu 定义。该标准为以太坊上的一些新功能和即将开发的功能奠定了基础。在本文中,我们将回顾柏林升级引入的一些标准以及未来有可能引入的其它标准。
标准化的事务封套
过去,以太坊的事务都采用同一种格式。每个以太坊事务都有 6 个字段:nonce、gasprice、gaslimit、to address、value、data、v、r 和 s。这些字段需要经过 RLP 编码,如下所示:
RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])
EIP 2718 为类型化事务定义了一种新的通用封套。在新的标准下,事务如下所示:
TransactionType || TransactionPayload
上述字段的定义是:
-
TransactionType
:0
至0x7f
范围内的某个值,最多可代表 128 种事务类型。 -
TransactionPayload
:由事务类型定义的任意一个字节数组。
将上述字段连接(合并)起来,即可得到一个类型化事务。EIP 2718 没有为事务的有效负载定义格式。因此,事务的有效负载可以是任意一段经过编码的字节序列,只要采用符合新的事务类型(如 RLP、SSZ 等)定义的编码器即可。之所以选择简单的字节相连方式,是因为读取字节数组的第一个字节非常简单,无需使用任何库或工具。也就是说,你不需要使用 RLP 或 SSZ 解析器来判断事务类型。
这个方法可以避免新的 EIP 在引入新的事务类型时增加现有事务格式的复杂性,并让不同的以太坊工具(客户端、库)更容易区分不同的事务。
在增加复杂性这一点上,EIP-155 就是一个很好的例子。它通过在事务中引入链 ID 来实现重放攻击保护。由于在事务参数中增加新的字段会破坏向后兼容性,链 ID 被编码进了事务签名的恢复参数(v),就像我在上一篇关于数字签名的文章中解释的那样。实行 EIP 2718 后,我们可以在不影响向后兼容性的情况下定义新的事务类型。
向后兼容性和传统事务
EIP 2718 的一大特点就是向后兼容。EIP 2718 是完全向后兼容的。也就是说,现有的工具、库、(硬件)钱包和事务都是开箱即用的,但是它们无法使用 EIP 2718(以及采用 EIP 2718 的标准)提供的新 “功能”。以太坊网络上的新事务依然可以使用旧的事务格式(即,传统事务)。
新的事务类型最多可达
0x7f
种。选择这一上限是为了保证向后兼容传统事务。经过 RLP 编码的事务的第一个字节始终大于或等于
0xc0
,因此类型化事务永远不会与传统事务产生冲突,而且类型化事务和传统事务之间可以通过第一个字节来区分。
EIP 2718 本身并未定义任何事务类型,不过已经出现了一些采用这一新标准的 EIP :
-
EIP 1559:改革 ETH 1.0 链的交易费市场。你肯定听说过这个 EIP。
-
EIP 2711:代付事务、限期事务和批量事务。这个 EIP 同样由Micah Zoltu 提出,EIP-2718 中定义的标准就是为此创建的。
-
EIP 2930:可选访问列表。
我们将在下文详细解释其中一些标准。
为什么要引入新的事务类型?
新的事务类型可以实现原本需要借助于 Solidity 合约或第三方解决方案的功能集成。以限期事务为例。在现有解决方案中,你可以将资金发送至 Solidity 合约,签署一个事务并将其发送到专门的节点,让该事务获得额外的参数(例如,有效期)。然后,该节点会处理该事务,确保它在有效期之前执行,否则该事务不会被广播。一些 dApp 和合约(如 Uniswap)内置该功能,但是对于大多数事务而言很难实现。
EIP 2711 可以将该功能添加到以太坊网络上,同时保证向后兼容传统事务(正如上文所述),而且无需使用智能合约或专门的节点。但是,EIP 2711 目前还是草案,我们还无法确定它近期是否会在以太坊网络上实行。EIP 2711 也有可能被拆分成几个小的 EIP(如 EIP 3074)。
EIP 1559 提出的新的事务格式
在 EIP 1559 中,gas 的运作方式发生了巨大变化:gas 会被部分销毁,不再全部支付给矿工。本文不会具体阐述 EIP 1559 的所有变化,但是 EIP 1559 确实提出了一种新的事务格式:
0x02 || RLP([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, accessList, signatureYParity, signatureR, signatureS])
最显著的变化包括:
-
用 “每单位 gas 的最高优先费用(max priority fee per gas)” 和 “每单位 gas 的最高费用(max fee per gas)” 来代替 gas price。
-
链 ID 是单独编码的,不再包含在签名
v
值内。这实际上是使用更简单的实现来代替 EIP 155。 -
签名
v
值变成了一个简单的校验位(“签名 Y 校验位”),不是 0 就是 1,具体取决于使用椭圆曲线上的哪个点。
EIP 1559 还提供了一种基于 EIP 2930 指定访问列表的方法。这样可以减少事务的 gas 成本。
由于 EIP 1559 极大地改变了 gas 费的运作方式,它并不能直接兼容传统事务。为了保证向后兼容性,EIP 1559 提出了一种将传统事务升级成兼容 EIP 1559 事务的方法,即,使用 “每单位 gas 的最高优先费用” 和 “每单位 gas 的最高费用” 来代替 “gas 价格”。
原生元事务和批量事务
元事务诞生已经有几年了,但是到目前为止都需要依靠智能合约。和限期事务一样,元事务也要求用户将以太币发送至专为元事务创建的智能合约。
EIP 2711 使得原生元事务(又称代付事务)和批量事务成为可能,无需依赖于智能合约。这里定义了一个新的事务格式,事务类型是
0x02
(但是事务类型可能会更改,因为 EIP-1559 也使用同一个事务类型标识)。交易如下所示:
0x02 || RLP([...SenderPayload, ...SenderSignature, ...GasPayerPayload, ...GasPayerSignature])
EIP 2711 主要包括 gas 付款方(用来支付事务 gas 费的账户)的有效负载(可选)和签名。这样一来,即使不持有任何以太币的地址也能发送 ERC 20 代币。
发送方的有效负载和签名等均基于事务子类型(1 至 4)定义。例如,如果交易类型为
1
,发送方的有效负载被定义为:
[1, ChildTransaction[], nonce, ChainId, ValidUntil, gasLimit, gasPrice]
ChildTransaction
被定义为
[to, value, data]
,可以在单个事务内指定收款方地址、值和数据。例如,
ChildTransaction
可以用来在单笔事务中调用 ERC 20 的
approve
和
transferFrom
。
如果你想了解更多关于 EIP 2711 的事务子类型的信息,我建议你阅读 EIP 2711 的规范。
结论
类型化事务为以太坊网络带来了更多可能性。我们在创建类型化事务时不会增加以太坊客户端、库和其它工具的复杂性。
目前,由于 EIP 2718 最近才被添加到网络中,新的事务类型还没有得到广泛应用,但是目前还有一些很棒的 EIP 正在开发中,例如,EIP 2711 提出了限期事务、批量事务和代付事务(即,元事务)。由于以太坊上可以定义新的事务类型,提出新的 EIP 也会变得更容易。