EIP-3074:提升以太坊用户体验

EIP 3074 为以太坊带来了很多新的可能。AUTHAUTHCALL 使得外部账户能够将账户的控制权授予智能合约调用者,从而实现批量事务和赞助事务等新的事务类型。然而,该 EIP 也极大地改变了事务在以太坊上的运作方式,因此在主网上激活该 EIP 之前,我们需要更深入地思考其安全性。

如果你是以太坊上的活跃用户,那么你大概率会持有一些 (ERC 20)代币,用来与以太坊生态中的各种 DeFi 项目进行交互。但是,这么做的前提是[你必须持有 ETH](https://support.mycrypto.com/general-knowledge/ethereum-blockchain/what-is-gas),因为 ERC 20 代币无法用来支付以太坊的手续费。另外,在向智能合约发送代币时,你通常需要执行两个事务:一个用来*许可* 目标合约使用你的代币,另一个用来将代币*转移* 到目标合约中。 [EIP-3074](https://eips.ethereum.org/EIPS/eip-3074) 可以让智能合约 *代表* 外部账户(就是普通的以太坊地址)发送事务,从而解决了上述乃至更多问题。 EIP 3074 引入了 `AUTH` 和 `AUTHCALL` 这两个 EVM 指令。第一个指令基于 ECDSA 签名设置环境变量`authorized`,第二个指令则作为 `authorized` 发送调用。这本质上就是向智能合约授予外部账户的控制权。 ![1](media/a4efa42421ab45079f9366022547baa2.png) 通过 `AUTH` 和 `AUTHCALL` EVM 指令(又称操作码),智能合约可以基于[已签署消息](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7)获得一个外部账户的授权,并代替该外部账户发送事务。这带来了很多可能性,如: * **赞助事务**(又称元事务):支付来自另一个账户的交易的 gas。这样一来,不持有 ETH 的地址也能发送代币。 * **批量事务**:通过单个调用发送多个事务。这样可以确保两个或以上的事务在同一个区块中执行,还可以降低交易费。 * **提升用户体验**:例如,你可以在单个事务中调用 `approve` 和 `transferFrom`。 不同于现有的解决方案,EIP 3074 不需要智能合约钱包。你可以直接将事务发送给负责执行事务的调用者(invoker)。调用者是无状态的免信任型智能合约,而且不需要你事先将余额发送到智能合约。EIP 3074 也没有引入新的[事务类型](https://blog.mycrypto.com/new-transaction-types-on-ethereum/)。从技术层面上来看,由于只引入了两种新的 EVM 指令,EIP 3074 实现起来理应更容易。 只可惜 EIP 3074 依然在审查中,而且由于种种(安全方面的)担忧,目前还不知道将于何时启用。如果你现在想要体验一把,可以使用 [Puxi 测试网](https://github.com/quilt/puxi)。在本文中,我将详细介绍 EIP 3074 的工作原理。 如果你想看一下 EIP 3074 的实际运行效果,我编写了一个(批量)事务调用者合约作为示例。点击下方链接,即可访问: [https://github.com/Mrtenz/transaction-invoker](https://github.com/Mrtenz/transaction-invoker) 请注意,这个合约没有经过审计,而且只是概念证明。请勿在生产环境中使用。 ## AUTH 和 AUTHCALL 操作码 EIP 3074 定义了两个新的操作码,可由智能合约调用: * `AUTH`(`0xf6`)—— 基于签名和 commit(提交)提出授权的外部账户。共有 4 个输入参数:`commit`以及签名的 `yParity`、`r` 和 `s`。 * `AUTHCALL`(`0xf7`) ——代替已授权的外部账户发送调用(事务) 。共有 8 个输入参数:`gas`、`addr`、`value`、`valueExt`、`argsOffset`、`argsLength`、`retOffset`和`retLength`。 与现有的`CALL` 操作码相似。 确认外部账户的授权需要来自该外部账户的签名消息。调用 `AUTH` 的智能合约可以通过消息签名复原出签名者,然后将其设置成 `authorized` EVM 环境变量。这样一来,该智能合约每次调用 `AUTHCALL` 时,调用者都会被设置成`authorized`地址。当被调用的智能合约调用 `CALLER`(例如,通过 Solidity 的 `msg.sender`)时,将由已授权的外部账户的地址而非调用者地址(智能合约)执行调用。 发送一个或多个事务的基本流程如下图所示: ![2](media/5b70e3252f214e19a28c40f52dbc4a8a.png) - 上图显示了 EIP 3074 的基本流程,其中调用者合约发送多个事务 - 1. 外部账户签署授权消息; 2. 外部账户或其他 gas 支付方将事务数据和授权消息发送给调用者合约; 3. 调用者合约使用 `AUTH` 操作码执行授权,并使用 `AUTHCALL` 操作码发送事务。 将事务发送到合约的是谁并不重要,只要外部账户的签名是有效的即可。因此,其他人(或账户)也可以发送事务。 请注意,目前无法使用 EIP 3074 通过外部账户发送 ETH。这样做会极大地改变当前的一些重要假设,例如,检查事务是否有效。调用者需要使用自己的 ETH 余额来发送 ETH。但是,你可以将 ETH 发送给调用者,并由调用者代为发送。目前,`AUTHCALL` 操作码所包含的 `valueExt` 字段必须被硬编码成 0。将来,如果找到适当的解决方案,我们可以更改这个字段,允许调用者外部账户发送 ETH。 ## 授权消息和 commit 为了执行授权,外部账户必须签署特定格式的消息: ``` 0x03 || <Padded invoker address> || <Commit> ``` (注:`||` 用作字节连接运算符。) 这个消息包含三个部分:一个魔术字节(`0x03`)、填充成 32 字节的调用者地址(执行authorize的智能合约的地址)以及一个 32 字节的 commit。 ![3](media/6c4e8049ebd649429b0ab5abef8550f1.png) \- 授权消息格式,包含一个 commit 示例 - 该 commit 描述了外部账户提交的数据,并且可以根据调用的某些属性计算得出,例如,地址、值和 nonce 的哈希值。调用者合约可以根据属性重新计算出 commit,如果这些字段都正确的话,就会执行授权。 假设我们想要发送以下事务(JSON 格式): ``` [ { "to": "0x6b175474e89094c44da98b954eedeac495271d0f", "value": 123, "nonce": 0 }, { "to": "0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520", "value: 123, "nonce": 1 } ] ``` 我们可以对这些字段进行哈希计算(例如,用确定性的方式将它们连接起来,或使用 [EIP 712](https://eips.ethereum.org/EIPS/eip-712) 之类的规范),并将得到的哈希值用作 commit。 我们可以在智能合约中提供要发送的事务和授权消息的签名,如 JSON 数据所示。合约函数就如下面这个例子所示: ``` function sendTransactions(Transaction[] calldata transactions, Signature calldata signature) external; ``` 智能合约根据 `transactions` 重新计算 commit,并将这个 commit(连同签名一起)提供给`AUTH`调用。此举的目的是找回签名者的地址,如果计算得到的 commit 无效,根据签名找回的地址将是错误的,也就是说事务将失败。 调用者对 commit 的安全性负全责。你可以将 `0x0` 作为 commit 来签署消息,并授予智能合约对外部账户的完整访问权。前几版 EIP-3074 对 commit 的格式要求更为严格,包括重放保护等,但是后面为了提高灵活性已经将其移除。这就要求你在与调用者进行交互时必须信任对方。 ## 局限性和安全隐患 由于能够根据签名更改 `CALLER`,EIP 3074 极大地改变了 EVM 的运作方式。这会为新合约和现有合约引入潜在漏洞。因此,[EIP 3074 已经经过正式审计](https://notes.ethereum.org/@djrtwo/eip-3074-audit-rfp)。 下文解释了一些安全隐患。由于种种原因,EIP 3074 建议只与可信调用者交互。[MyCrypto](https://mycrypto.com/) 等钱包界面提供可信调用者白名单功能。使用该功能的用户只能为白名单内的调用者签署授权消息。 ### 弱 commit 和重放攻击 正如上文解释的那样,EIP 3074 没有为 commit 定义标准格式。调用者可以通过任意方式生成 commit。这意味着,调用者有责任确保 commit 的安全性,例如,抵御重放攻击。 如果 commit 不包含某种随机数,攻击者就可以轻松获取已签署的消息,再一次发送给调用者。恶意调用者完全不需要验证 commit,就可以获得外部账户的控制权。每次签署消息时,请你务必谨慎。 EIP 3074 通过将调用者的地址包含在授权消息内,提供了最基础的重放攻击保护。这样一来,恶意调用者就无法重放其他调用者的授权消息。 ### 可升级调用者 EIP 3074 明确声明调用者程序不可升级。如果调用者程序是可以升级的,攻击者就可以部署另一个版本的调用者,在不验证 commit 的情况下授予合约对外部账户的控制权。 ### 重入攻击 目前,智能合约可以使用 `require(tx.origin == msg.sender)` 来验证事务是否来自外部账户(而非另一个合约)。这样可以在一定程度上防止重入攻击,因为它可以防止合约调用该函数。 EIP 3074 也允许 `tx.origin` 成为授权消息的签名者。调用者执行的任何 `AUTHCALL` 都会导致 `tx.origin == msg.sender` 成真,即使这个调用是由智能合约执行的,因此很有可能遭到重入攻击。EIP 3074 指出:“……本 EIP 的作者并未找到任何有关这种重入攻击的例子,尽管没有进行详尽的搜索。” ## 结论 EIP 3074 为以太坊带来了很多新的可能。`AUTH` 和 `AUTHCALL` 使得外部账户能够将账户的控制权授予智能合约调用者,从而实现批量事务和赞助事务等新的事务类型。然而,该 EIP 也极大地改变了事务在以太坊上的运作方式,因此在主网上激活该 EIP 之前,我们需要更深入地思考其安全性。 ## 联系我们 * [Twitter](https://twitter.com/mycrypto) * [Telegram](https://t.me/mycryptoHQ) * [Discord](https://discord.gg/hGV8C5c) * [GitHub](https://github.com/MyCryptoHQ) * [Help & Support](https://support.mycrypto.com/) * [Press Inquiries](http://press@mycrypto.com) (完) --- **原文链接:** [https://blog.mycrypto.com/eip-3074/](https://blog.mycrypto.com/eip-3074/) **作者:** Maarten Zuidhoorn **翻译&校对:** 闵敏 & 阿剑 --- 本文首发于:https://ethfans.org/posts/eip-3074-introduction-by-MyCrypto

如果你是以太坊上的活跃用户,那么你大概率会持有一些 (ERC 20)代币,用来与以太坊生态中的各种 DeFi 项目进行交互。但是,这么做的前提是你必须持有 ETH,因为 ERC 20 代币无法用来支付以太坊的手续费。另外,在向智能合约发送代币时,你通常需要执行两个事务:一个用来许可 目标合约使用你的代币,另一个用来将代币转移 到目标合约中。

EIP-3074 可以让智能合约 代表 外部账户(就是普通的以太坊地址)发送事务,从而解决了上述乃至更多问题。

EIP 3074 引入了 AUTHAUTHCALL 这两个 EVM 指令。第一个指令基于 ECDSA 签名设置环境变量authorized,第二个指令则作为 authorized 发送调用。这本质上就是向智能合约授予外部账户的控制权。

通过 AUTHAUTHCALL EVM 指令(又称操作码),智能合约可以基于已签署消息获得一个外部账户的授权,并代替该外部账户发送事务。这带来了很多可能性,如:

  • 赞助事务(又称元事务):支付来自另一个账户的交易的 gas。这样一来,不持有 ETH 的地址也能发送代币。
  • 批量事务:通过单个调用发送多个事务。这样可以确保两个或以上的事务在同一个区块中执行,还可以降低交易费。
  • 提升用户体验:例如,你可以在单个事务中调用 approvetransferFrom

不同于现有的解决方案,EIP 3074 不需要智能合约钱包。你可以直接将事务发送给负责执行事务的调用者(invoker)。调用者是无状态的免信任型智能合约,而且不需要你事先将余额发送到智能合约。EIP 3074 也没有引入新的事务类型。从技术层面上来看,由于只引入了两种新的 EVM 指令,EIP 3074 实现起来理应更容易。

只可惜 EIP 3074 依然在审查中,而且由于种种(安全方面的)担忧,目前还不知道将于何时启用。如果你现在想要体验一把,可以使用 Puxi 测试网。在本文中,我将详细介绍 EIP 3074 的工作原理。

如果你想看一下 EIP 3074 的实际运行效果,我编写了一个(批量)事务调用者合约作为示例。点击下方链接,即可访问:

https://github.com/Mrtenz/transaction-invoker

请注意,这个合约没有经过审计,而且只是概念证明。请勿在生产环境中使用。

AUTH 和 AUTHCALL 操作码

EIP 3074 定义了两个新的操作码,可由智能合约调用:

  • AUTH0xf6)—— 基于签名和 commit(提交)提出授权的外部账户。共有 4 个输入参数:commit以及签名的 yParityrs
  • AUTHCALL0xf7) ——代替已授权的外部账户发送调用(事务) 。共有 8 个输入参数:gasaddrvaluevalueExtargsOffsetargsLengthretOffsetretLength。 与现有的CALL 操作码相似。

确认外部账户的授权需要来自该外部账户的签名消息。调用 AUTH 的智能合约可以通过消息签名复原出签名者,然后将其设置成 authorized EVM 环境变量。这样一来,该智能合约每次调用 AUTHCALL 时,调用者都会被设置成authorized地址。当被调用的智能合约调用 CALLER(例如,通过 Solidity 的 msg.sender)时,将由已授权的外部账户的地址而非调用者地址(智能合约)执行调用。

发送一个或多个事务的基本流程如下图所示:

  • 上图显示了 EIP 3074 的基本流程,其中调用者合约发送多个事务 -
  1. 外部账户签署授权消息;
  2. 外部账户或其他 gas 支付方将事务数据和授权消息发送给调用者合约;
  3. 调用者合约使用 AUTH 操作码执行授权,并使用 AUTHCALL 操作码发送事务。

将事务发送到合约的是谁并不重要,只要外部账户的签名是有效的即可。因此,其他人(或账户)也可以发送事务。

请注意,目前无法使用 EIP 3074 通过外部账户发送 ETH。这样做会极大地改变当前的一些重要假设,例如,检查事务是否有效。调用者需要使用自己的 ETH 余额来发送 ETH。但是,你可以将 ETH 发送给调用者,并由调用者代为发送。目前,AUTHCALL 操作码所包含的 valueExt 字段必须被硬编码成 0。将来,如果找到适当的解决方案,我们可以更改这个字段,允许调用者外部账户发送 ETH。

授权消息和 commit

为了执行授权,外部账户必须签署特定格式的消息:

0x03 || &lt;Padded invoker address> || &lt;Commit>

(注:|| 用作字节连接运算符。)

这个消息包含三个部分:一个魔术字节(0x03)、填充成 32 字节的调用者地址(执行authorize的智能合约的地址)以及一个 32 字节的 commit。

- 授权消息格式,包含一个 commit 示例 -

该 commit 描述了外部账户提交的数据,并且可以根据调用的某些属性计算得出,例如,地址、值和 nonce 的哈希值。调用者合约可以根据属性重新计算出 commit,如果这些字段都正确的话,就会执行授权。

假设我们想要发送以下事务(JSON 格式):

[
  {
    "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
    "value": 123,
    "nonce": 0
  },
  {
    "to": "0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520",
    "value: 123,
    "nonce": 1
  }
]

我们可以对这些字段进行哈希计算(例如,用确定性的方式将它们连接起来,或使用 EIP 712 之类的规范),并将得到的哈希值用作 commit。

我们可以在智能合约中提供要发送的事务和授权消息的签名,如 JSON 数据所示。合约函数就如下面这个例子所示:

function sendTransactions(Transaction[] calldata transactions, Signature calldata signature) external;

智能合约根据 transactions 重新计算 commit,并将这个 commit(连同签名一起)提供给AUTH调用。此举的目的是找回签名者的地址,如果计算得到的 commit 无效,根据签名找回的地址将是错误的,也就是说事务将失败。

调用者对 commit 的安全性负全责。你可以将 0x0 作为 commit 来签署消息,并授予智能合约对外部账户的完整访问权。前几版 EIP-3074 对 commit 的格式要求更为严格,包括重放保护等,但是后面为了提高灵活性已经将其移除。这就要求你在与调用者进行交互时必须信任对方。

局限性和安全隐患

由于能够根据签名更改 CALLER,EIP 3074 极大地改变了 EVM 的运作方式。这会为新合约和现有合约引入潜在漏洞。因此,EIP 3074 已经经过正式审计。

下文解释了一些安全隐患。由于种种原因,EIP 3074 建议只与可信调用者交互。MyCrypto 等钱包界面提供可信调用者白名单功能。使用该功能的用户只能为白名单内的调用者签署授权消息。

弱 commit 和重放攻击

正如上文解释的那样,EIP 3074 没有为 commit 定义标准格式。调用者可以通过任意方式生成 commit。这意味着,调用者有责任确保 commit 的安全性,例如,抵御重放攻击。

如果 commit 不包含某种随机数,攻击者就可以轻松获取已签署的消息,再一次发送给调用者。恶意调用者完全不需要验证 commit,就可以获得外部账户的控制权。每次签署消息时,请你务必谨慎。

EIP 3074 通过将调用者的地址包含在授权消息内,提供了最基础的重放攻击保护。这样一来,恶意调用者就无法重放其他调用者的授权消息。

可升级调用者

EIP 3074 明确声明调用者程序不可升级。如果调用者程序是可以升级的,攻击者就可以部署另一个版本的调用者,在不验证 commit 的情况下授予合约对外部账户的控制权。

重入攻击

目前,智能合约可以使用 require(tx.origin == msg.sender) 来验证事务是否来自外部账户(而非另一个合约)。这样可以在一定程度上防止重入攻击,因为它可以防止合约调用该函数。

EIP 3074 也允许 tx.origin 成为授权消息的签名者。调用者执行的任何 AUTHCALL 都会导致 tx.origin == msg.sender 成真,即使这个调用是由智能合约执行的,因此很有可能遭到重入攻击。EIP 3074 指出:“……本 EIP 的作者并未找到任何有关这种重入攻击的例子,尽管没有进行详尽的搜索。”

结论

EIP 3074 为以太坊带来了很多新的可能。AUTHAUTHCALL 使得外部账户能够将账户的控制权授予智能合约调用者,从而实现批量事务和赞助事务等新的事务类型。然而,该 EIP 也极大地改变了事务在以太坊上的运作方式,因此在主网上激活该 EIP 之前,我们需要更深入地思考其安全性。

联系我们

  • Twitter
  • Telegram
  • Discord
  • GitHub
  • Help & Support
  • Press Inquiries

(完)

原文链接: https://blog.mycrypto.com/eip-3074/ 作者: Maarten Zuidhoorn 翻译&校对: 闵敏 & 阿剑

本文首发于:https://ethfans.org/posts/eip-3074-introduction-by-MyCrypto

区块链技术网。

  • 发表于 2021-06-26 11:14
  • 阅读 ( 371 )
  • 学分 ( 6 )
  • 分类:以太坊

评论