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