{"content":{"title":"支持 multicall 的JSON-RPC 方法 eth_simulateV1 在多网络可用","body":">- 原文链接：[mirror.xyz/killaridev.e...](https://mirror.xyz/killaridev.eth/eQhG3pw-P-iqdLWaEFJ_nKzr5SdaoY00ECZYcQuymAM)\r\n>- 译者：[AI翻译官](https://learnblockchain.cn/people/19584)，校对：[翻译小组](https://learnblockchain.cn/people/412)\r\n>- 本文链接：[learnblockchain.cn/article…](https://learnblockchain.cn/article/10218)\r\n    \r\n`eth_simulateV1` 方法在发布 [Geth v1.14.9](https://github.com/ethereum/go-ethereum/releases/tag/v1.14.9) 和 [Nethermind v1.28.0](https://github.com/NethermindEth/nethermind/releases/tag/1.28.0) 后已经在以太坊主网上线。它也支持 Base、Optimism 和 Gnosis 等网络。\r\n\r\n`eth_simulateV1` 方法是 `eth_call` 的增强版，旨在支持multicall和更高级的功能。以前，multicall功能是通过以下工具实现的：\r\n\r\n1.  [Alchemy forking](https://docs.alchemy.com/docs/how-to-fork-ethereum-mainnet)\r\n    \r\n2.  [Hardhat forking](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks)\r\n    \r\n3.  [Flashbots eth_callBundle](https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint)\r\n    \r\n4.  [Multicall contracts](https://github.com/mds1/multicall)\r\n    \r\n\r\n虽然这些方法各有优点，但缺乏标准化。此外，multicall合约仅限于在同一合约内进行多次调用，无法模拟多个交易。\r\n\r\n相比之下，`eth_simulateV1` 提供了通过 JSON-RPC 进行multicall的**标准化方法**（ [执行规范 484](https://github.com/ethereum/execution-apis/pull/484)）。它保留了 `eth_call` 的核心功能，同时引入了显著的改进。\r\n\r\n### `eth_simulateV1` 的主要特性\r\n\r\n1.  **跨区块调用：** 定义自定义区块变量以进行细粒度模拟。\r\n    \r\n2.  **状态覆盖(Overrides)：** 在模拟过程中修改账户余额或替换合约代码。\r\n    \r\n3.  **预编译重载(Overrides)：** 用自定义代码替代预编译合约。\r\n    \r\n4.  **增强的日志记录：** 访问详细的事件和 ETH 转账日志，超出单次调用结果。\r\n    \r\n5.  **验证模式：** 强制施加更严格的规则，以确保链上兼容性。\r\n    \r\n\r\n这些功能为开发者提供了更多的权力和灵活性，使得 `eth_simulateV1` 成为高级交易模拟的强大工具。\r\n\r\n在这篇博客中，我们将深入探讨这些新功能，并展示它们在改善以太坊开发工作流程中的潜力。\r\n\r\n## 1) 在区块内模拟调用\r\n\r\n使用 `eth_call` 函数，你可以在用户自定义的区块内执行单个调用。相比之下，通过 `eth_simulateV1`， 提供跨不同区块进行调用的能力，并提供对每个调用的区块参数进行重载的灵活性。\r\n\r\n以下是一个简单的 `eth_simulateV1` 调用示例，展示了如何定义两个区块 `1001`（`0x3e9`）和 `2001`（`0x7d1`）并在其内部放置调用：\r\n```json\r\n    {\r\n      \"jsonrpc\": \"2.0\",\r\n      \"id\": 1,\r\n      \"method\": \"eth_simulateV1\",\r\n      \"params\": [\r\n        {\r\n          \"blockStateCalls\": [\r\n            {\r\n              \"blockOverrides\": {\r\n                \"number\": \"0x3e9\",\r\n                \"time\": \"0x3e9\",\r\n                \"gasLimit\": \"0x3ec\",\r\n                \"feeRecipient\": \"0xc200000000000000000000000000000000000000\",\r\n                \"prevRandao\": \"0xc300000000000000000000000000000000000000000000000000000000000000\",\r\n                \"baseFeePerGas\": \"0x3ef\",\r\n                \"blobBaseFee\": \"0x15\"\r\n              },\r\n              \"calls\": [ \"eth_calls\" ]\r\n            },\r\n            {\r\n              \"blockOverrides\": {\r\n                \"number\": \"0x7d1\",\r\n                \"time\": \"0x7d1\",\r\n                \"gasLimit\": \"0x3ec\",\r\n                \"feeRecipient\": \"0xc200000000000000000000000000000000000000\",\r\n                \"prevRandao\": \"0xc300000000000000000000000000000000000000000000000000000000000000\",\r\n                \"baseFeePerGas\": \"0x3ef\",\r\n                \"blobBaseFee\": \"0x15\"\r\n              },\r\n              \"calls\": [ \"more eth_calls\" ]\r\n            }\r\n          ]\r\n        },\r\n        \"latest\"\r\n      ]\r\n    }\r\n   \r\n```\r\n\r\n在定义区块时，你可以重载(Overrides)七个参数：`number`、`time`、`gasLimit`、`feeRecipient`、`prevRandao`、`baseFeePerGas`和`blobBaseFee`。所有这些参数，包括 `number` 和 `time`，都可以自定义。然而，`number` 必须始终递增，而 `time` 必须递增或保持不变。\r\n\r\n这些变量的一个有趣特点是，能够跳过时间或区块，例如，你可以定义区块 `10`，然后直接跳到区块 `20`。这允许你在不指定每个中间区块的情况下模拟未来事件。在使用 `eth_simulateV1` 方法时，区块 `10` 和 `20` 之间的所有区块都会被模拟并返回。\r\n\r\n请注意，单次调用中可创建的区块数有最大限制。默认情况下，该限制为 `256` 个区块，尽管可以根据客户端进行调整。\r\n\r\n此外，还对模拟的总 gas 消耗和返回有效载荷的大小设定了限制。这些限制有助于管理单个 `eth_simulateV1` 调用对节点造成的负载。gas 和有效载荷大小限制也可以根据客户端自定义。\r\n\r\n## 2) 状态覆盖\r\n\r\n状态覆盖允许你修改任何账户的 `balance`、`code`、`nonce` 和 `state`。`state`变量可以替换一个账户的整个状态，而 `stateDiff` 允许你通过逐步应用更改来增强现有状态。\r\n\r\n这些强大的账户状态操控工具提供以下能力：\r\n\r\n1.  **设置账户余额：** 调整任何账户的余额，从而有效地铸造 ETH 以用于 DeFi 应用。\r\n    \r\n2.  **代币铸造：** 修改 ERC20 智能合约的状态，直接向你的账户铸造代币。\r\n    \r\n3.  **智能合约替换：** 替换现有智能合约的代码，以绕过其典型的检查或限制。\r\n    \r\n4.  **即时合约部署：** 模拟智能合约的部署并立即与之互动，无需实际在链上部署。\r\n    \r\n\r\n考虑一个简单的智能合约，用于检索账户余额：\r\n```solidity\r\n    pragma solidity 0.8.18;\r\n    \r\n    contract BalanceGetter {\r\n    \tfunction getBalance(address addr) view external returns (uint256) {\r\n    \t\treturn address(addr).balance;\r\n    \t}\r\n    }\r\n```    \r\n\r\n以下是一个调用，它设置我们的余额，通过直接设置一些账户状态来部署 `BalanceGetter` 合约，并调用它以请求我们的余额：\r\n```json\r\n    {\r\n      \"jsonrpc\": \"2.0\",\r\n      \"id\": 1,\r\n      \"method\": \"eth_simulateV1\",\r\n      \"params\": [\r\n        {\r\n          \"blockStateCalls\": [\r\n            {\r\n              \"stateOverrides\": {\r\n                \"0xc000000000000000000000000000000000000000\": {\r\n                  \"balance\": \"0x2710\"\r\n                },\r\n                \"0xc200000000000000000000000000000000000000\": {\r\n                  \"code\": \"0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f8b2cb4f14610030575b600080fd5b61004a600480360381019061004591906100e4565b610060565b604051610057919061012a565b60405180910390f35b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100b182610086565b9050919050565b6100c1816100a6565b81146100cc57600080fd5b50565b6000813590506100de816100b8565b92915050565b6000602082840312156100fa576100f9610081565b5b6000610108848285016100cf565b91505092915050565b6000819050919050565b61012481610111565b82525050565b600060208201905061013f600083018461011b565b9291505056fea2646970667358221220172c443a163d8a43e018c339d1b749c312c94b6de22835953d960985daf228c764736f6c63430008120033\"\r\n                }\r\n              },\r\n              \"calls\": [\r\n                {\r\n                  \"from\": \"0xc000000000000000000000000000000000000000\",\r\n                  \"to\": \"0xc200000000000000000000000000000000000000\",\r\n                  \"input\": \"0xf8b2cb4f000000000000000000000000c000000000000000000000000000000000000000\"\r\n                }\r\n              ]\r\n            }\r\n          ]\r\n        },\r\n        \"latest\"\r\n      ]\r\n    }\r\n```  \r\n    \r\n\r\n然后返回以下 JSON 响应：\r\n\r\n```json\r\n    {\r\n        \"jsonrpc\": \"2.0\",\r\n        \"id\": 1,\r\n        \"result\": [\r\n            {\r\n                \"baseFeePerGas\": \"0x0\",\r\n                \"blobGasUsed\": \"0x0\",\r\n                \"calls\": [\r\n                    {\r\n                        \"returnData\": \"0x0000000000000000000000000000000000000000000000000000000000002710\",\r\n                        \"logs\": [],\r\n                        \"gasUsed\": \"0x55b3\",\r\n                        \"status\": \"0x1\"\r\n                    }\r\n                ],\r\n                \"difficulty\": \"0x0\",\r\n                \"excessBlobGas\": \"0x3220000\",\r\n                \"extraData\": \"0x\",\r\n                \"gasLimit\": \"0x1c9c380\",\r\n                \"gasUsed\": \"0x55b3\",\r\n                \"hash\": \"0x4342f0ab870175757176d5888e82f27523a6e1d52c0ac20a6ddf599d54ce0e04\",\r\n                \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\r\n                \"miner\": \"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5\",\r\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\r\n                \"nonce\": \"0x0000000000000000\",\r\n                \"number\": \"0x1455a09\",\r\n                \"parentBeaconBlockRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\r\n                \"parentHash\": \"0xb30e288a5518544cc71dd24389a21061adab20f45f17c0907054dccf7bf00c01\",\r\n                \"receiptsRoot\": \"0x4ce78e593fcb88a20d7bb31c27879f800551f4069371e576f7efad0d9615a960\",\r\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\r\n                \"size\": \"0x29b\",\r\n                \"stateRoot\": \"0xcfb988bd139a3f44aa79f9cbaba606429d76749fd18e1e8ca9a6612a4e0c8384\",\r\n                \"timestamp\": \"0x674f0627\",\r\n                \"totalDifficulty\": \"0xc70d815d562d3cfa955\",\r\n                \"transactions\": [\r\n                    \"0x96c6b7b5b4835fd518fd914feb586452cc797d332f1bd234f72c9e692c4c427a\"\r\n                ],\r\n                \"transactionsRoot\": \"0xebe30ac336ac6714af65c684e278799f70965b18ae12e9b368056640ac111650\",\r\n                \"uncles\": [],\r\n                \"withdrawals\": [],\r\n                \"withdrawalsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\r\n            }\r\n        ]\r\n    }\r\n```  \r\n\r\n这个响应的详细程度显著高于标准的 `eth_call`。它包含一个结果数组（`result: []`），其中每个元素代表一个区块，包含了执行调用的结果。如前所述，`eth_simulateV1` 将调用组织成区块，提供有关区块及其相应调用结果的全面信息。本质上，`eth_simulateV1` 返回的是你从 `eth_getBlockByNumber` 获取的模拟区块数据。然而，由于这些区块仅在 `eth_simulateV1` 调用期间存在，因此此信息直接包含在响应中。\r\n\r\n在区块结果中，还返回有关调用执行的信息：\r\n\r\n    \"calls\": [\r\n        {\r\n          \"returnData\": \"0x0000000000000000000000000000000000000000000000000000000000002710\",\r\n          \"logs\": [],\r\n          \"gasUsed\": \"0x55b3\",\r\n          \"status\": \"0x1\"\r\n        }\r\n      ]\r\n    \r\n\r\n`returnData` 表示我们的余额，与合约的预期结果一致。此外，我们还包含了返回数据中的日志，尽管在此示例中没有日志。日志的包含标志着相较于先前 `eth_call` 方法的显著增强，后者仅返回了 `returnData` 字段。除此之外，我们提供了 `gasUsed` 字段，指示调用执行期间消耗的 gas 量。这些信息对 gas 估算计算非常有价值，并且对节点而言成本微乎其微，因为 gas 计算是过程的一部分。\r\n\r\n## 3) 预编译覆盖（override）\r\n\r\n由于预编译本质上是链上的账户，因此可以按照与其他账户重写相同的方式进行替换。然而，预编译具有一个独特的特点——一旦被覆盖，就无法直接在调用中访问原始预编译。虽然可以实现你自己的 Solidity 版本的 `ecrecover`，但这种方法往往会导致 gas 效率低下。为了解决这个问题，我们引入了一个名为 `movePrecompileToAddress` 的 `eth_simulateV1` 设置，使你能够覆盖预编译并随后将其移动到一个新账户。\r\n\r\n一个实用的应用场景是覆盖 `ecrecover` 以执行 Uniswap Permit2 兑换。要执行这样的兑换，用户必须签名一条链外消息，然后将其包含在链上以验证用户的批准。\r\n\r\n现在，让我们探讨如何模拟 Vitalik 账户（`0xd8da6bf26964af9d7eed9e03e53415d37aa96045`）的 USDC 到 WBTC 的兑换，并覆盖 `ecrecover`，而不需要访问 Vitalik 的私钥。\r\n\r\n下面是我们将用来替换 `ecrecover` 的合约。合约分为几个部分：\r\n\r\n1.  `overrideToAddress` 映射将包含我们希望覆盖以返回所选地址的 `ecrecover` 参数哈希。\r\n    \r\n2.  一个 fallback 方法在调用 `ecrecover` 时被调用，查看 `overrideToAddress` 映射中是否有任何覆盖。如果存在覆盖，方法会检索相关的账户。如果没有覆盖，方法将默认调用地址为 `0x123456` 的合约，实际的 `ecrecover` 实现会被迁移到该地址。\r\n    \r\n```solidity\r\n    pragma solidity 0.8.18;\r\n    \r\n    contract ecRecoverOverride {\r\n      mapping(bytes32 => address) overrideToAddress;\r\n      fallback (bytes calldata input) external returns (bytes memory) {\r\n        (bytes32 hash, uint8 v, bytes32 r, bytes32 s) = abi.decode(input, (bytes32, uint8, bytes32, bytes32));\r\n        address overridedAddress = overrideToAddress[keccak256(abi.encode(hash, v, r, s))];\r\n        if (overridedAddress == address(0x0)) {\r\n          (bool success, bytes memory data) = address(0x0000000000000000000000000000000000123456).call{gas: 10000}(input);\r\n          require(success, 'failed to call moved ecrecover at address 0x0000000000000000000000000000000000123456');\r\n          return data;\r\n        } else {\r\n          return abi.encode(overridedAddress);\r\n        }\r\n      }\r\n    }\r\n```    \r\n\r\n一旦合约编写完成，我们可以创建 `eth_simulateV1` 查询。这涉及两个调用：第一个是 授权 Uniswap 的 Permit2 合约，第二个是执行实际的兑换。为了使兑换成功，我们需要覆盖位于地址 `0x1` 的 `ecrecover`。这需要替换该地址的代码，将预编译移动到地址 `0x123456`，并用适当的覆盖更新 `overrideToAddress` 映射。\r\n\r\n```json\r\n    {\r\n    \t\"jsonrpc\": \"2.0\",\r\n    \t\"id\": 162,\r\n    \t\"method\": \"eth_simulateV1\",\r\n    \t\"params\": [\r\n    \t\t{\r\n    \t\t\t\"blockStateCalls\": [\r\n    \t\t\t\t{\r\n    \t\t\t\t\t\"calls\": [\r\n    \t\t\t\t\t\t{ // approve\r\n    \t\t\t\t\t\t\t\"type\": \"0x2\",\r\n    \t\t\t\t\t\t\t\"from\": \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\",\r\n    \t\t\t\t\t\t\t\"nonce\": \"0x481\",\r\n    \t\t\t\t\t\t\t\"maxFeePerGas\": \"0x10e2249a2c\",\r\n    \t\t\t\t\t\t\t\"maxPriorityFeePerGas\": \"0x5f5e100\",\r\n    \t\t\t\t\t\t\t\"gas\": \"0x12631\",\r\n    \t\t\t\t\t\t\t\"to\": \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\",\r\n    \t\t\t\t\t\t\t\"value\": \"0x0\",\r\n    \t\t\t\t\t\t\t\"input\": \"0x095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\r\n    \t\t\t\t\t\t\t\"chainId\": \"0x1\",\r\n    \t\t\t\t\t\t\t\"accessList\": []\r\n    \t\t\t\t\t\t},\r\n    \t\t\t\t\t\t{ // swap\r\n    \t\t\t\t\t\t\t\"type\": \"0x2\",\r\n    \t\t\t\t\t\t\t\"from\": \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\",\r\n    \t\t\t\t\t\t\t\"nonce\": \"0x482\",\r\n    \t\t\t\t\t\t\t\"maxFeePerGas\": \"0x11491519cc\",\r\n    \t\t\t\t\t\t\t\"maxPriorityFeePerGas\": \"0x5f5e100\",\r\n    \t\t\t\t\t\t\t\"gas\": \"0x424ee\",\r\n    \t\t\t\t\t\t\t\"to\": \"0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad\",\r\n    \t\t\t\t\t\t\t\"value\": \"0x0\",\r\n    \t\t\t\t\t\t\t\"input\": \"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000655f00d400000000000000000000000000000000000000000000000000000000000000030a080c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000658686d800000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad00000000000000000000000000000000000000000000000000000000655f00e000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000041a6b086e6ffec7e22a7cac3d71494f1c7ec44a85c66156aff9fe881bf1fb99bc053dc332293ea7dce14be4cb689d9b75e920b37deab9ed761325999e0b48a66bf1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000042c1d800000000000000000000000000000000000000000000000000072b3980a9ab9fe00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000072b3980a9ab9fe\",\r\n    \t\t\t\t\t\t\t\"chainId\": \"0x1\",\r\n    \t\t\t\t\t\t\t\"accessList\": []\r\n    \t\t\t\t\t\t}\r\n    \t\t\t\t\t],\r\n    \t\t\t\t\t\"stateOverrides\": {\r\n    \t\t\t\t\t\t\"0x0000000000000000000000000000000000000001\": { \r\n    \t\t\t\t\t\t\t\"state\": { // override the mapping\r\n    \t\t\t\t\t\t\t\t\"0x010d8fdb5b1199f6ac26d39281e100201200fbc7de5bcb9710c3dfeb475c65f6\": \"0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045\"\r\n    \t\t\t\t\t\t\t},\r\n                                // replace the ecrecover code with our own code\r\n    \t\t\t\t\t\t\t\"code\": \"0x608060405234801561001057600080fd5b506000366060600080600080868681019061002b9190610238565b935093509350935060008060008686868660405160200161004f94939291906102bd565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610191576000806212345673ffffffffffffffffffffffffffffffffffffffff166127108b8b6040516100fa929190610341565b60006040518083038160008787f1925050503d8060008114610138576040519150601f19603f3d011682016040523d82523d6000602084013e61013d565b606091505b509150915081610182576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017990610403565b60405180910390fd5b809750505050505050506101b9565b806040516020016101a29190610464565b604051602081830303815290604052955050505050505b915050805190602001f35b600080fd5b6000819050919050565b6101dc816101c9565b81146101e757600080fd5b50565b6000813590506101f9816101d3565b92915050565b600060ff82169050919050565b610215816101ff565b811461022057600080fd5b50565b6000813590506102328161020c565b92915050565b60008060008060808587031215610252576102516101c4565b5b6000610260878288016101ea565b945050602061027187828801610223565b9350506040610282878288016101ea565b9250506060610293878288016101ea565b91505092959194509250565b6102a8816101c9565b82525050565b6102b7816101ff565b82525050565b60006080820190506102d2600083018761029f565b6102df60208301866102ae565b6102ec604083018561029f565b6102f9606083018461029f565b95945050505050565b600081905092915050565b82818337600083830152505050565b60006103288385610302565b935061033583858461030d565b82840190509392505050565b600061034e82848661031c565b91508190509392505050565b600082825260208201905092915050565b7f6661696c656420746f2063616c6c206d6f7665642065637265636f766572206160008201527f742061646472657373203078303030303030303030303030303030303030303060208201527f3030303030303030303030303030313233343536000000000000000000000000604082015250565b60006103ed60548361035a565b91506103f88261036b565b606082019050919050565b6000602082019050818103600083015261041c816103e0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061044e82610423565b9050919050565b61045e81610443565b82525050565b60006020820190506104796000830184610455565b9291505056fea26469706673582212207ddee236692b0fb014c4a668a714cba393524150b3782202194780d8b923261464736f6c63430008120033\",\r\n    \t\t\t\t\t\t\t\"movePrecompileToAddress\": \"0x0000000000000000000000000000000000123456\"\r\n    \t\t\t\t\t\t}\r\n    \t\t\t\t\t},\r\n    \t\t\t\t\t\"blockOverride\": {\r\n    \t\t\t\t\t\t\"number\": \"0x11c507e\",\r\n    \t\t\t\t\t\t\"prevRandao\": \"0x1\",\r\n    \t\t\t\t\t\t\"time\": \"0x655ef9fb\",\r\n    \t\t\t\t\t\t\"gasLimit\": \"0x1c9c380\",\r\n    \t\t\t\t\t\t\"feeRecipient\": \"0x88c6c46ebf353a52bdbab708c23d0c81daa8134a\",\r\n    \t\t\t\t\t\t\"baseFee\": \"0x68b59f4cb\"\r\n    \t\t\t\t\t}\r\n    \t\t\t\t}\r\n    \t\t\t],\r\n    \t\t\t\"traceTransfers\": true,\r\n    \t\t\t\"validation\": false\r\n    \t\t},\r\n    \t\t\"0x11c507d\"\r\n    \t]\r\n    }\r\n```\r\n\r\n## 4) 事件日志与 ETH 转账日志\r\n\r\n`eth_call` RPC 方法仅返回与第一个调用的返回值对应的输出。然而，在许多情况下，合约执行各个阶段发出的事件提供了更深入的洞察，以了解发生了什么。为了解决这个问题，`eth_simulateV1` 在其输出中包含日志，提供了更全面的执行视图。\r\n\r\n除了这些日志，`eth_simulateV1` 还支持类似 ERC20 的以太坊转账日志。ETH 转账的日志可以通过 `traceTransfers` 标志进行开关控制。\r\n\r\n例如，通过覆盖 Dope Wars 的治理时间锁合约，我们可以模拟特定治理投票的结果。这种模拟已经可以使用 [The Interceptor](https://www.dark.florist/) 工具进行。\r\n```\r\n    {\r\n      \"jsonrpc\": \"2.0\",\r\n      \"id\": 204,\r\n      \"method\": \"eth_simulateV1\",\r\n      \"params\": [\r\n        {\r\n          \"blockStateCalls\": [\r\n            {\r\n              \"calls\": [\r\n                {\r\n                  \"type\": \"0x2\",\r\n                  \"from\": \"0xdbd38f7e739709fe5bfae6cc8ef67c3820830e0c\",\r\n                  \"nonce\": \"0x0\",\r\n                  \"maxFeePerGas\": \"0x0\",\r\n                  \"maxPriorityFeePerGas\": \"0x0\",\r\n                  \"to\": \"0xb57ab8767cae33be61ff15167134861865f7d22c\",\r\n                  \"value\": \"0x0\",\r\n                  \"input\": \"execute timelock\",\r\n                  \"chainId\": \"0x1\",\r\n                  \"accessList\": []\r\n                }\r\n              ],\r\n              \"stateOverrides\": {\r\n                \"0xb57ab8767cae33be61ff15167134861865f7d22c\": {\r\n                  \"stateDiff\": {},\r\n                  \"code\": \"Timelock contract replacement bytecode\"\r\n                }\r\n              },\r\n            }\r\n          ],\r\n          \"traceTransfers\": true,\r\n          \"validation\": false\r\n        },\r\n        \"0x11b1f64\"\r\n      ]\r\n    }\r\n```\r\n\r\n以下是 `eth_simulateV1` 的调用结果：\r\n```\r\n    {\r\n      \"returnData\": \"0x\",\r\n      \"logs\": [\r\n        {\r\n          \"address\": \"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\",\r\n          \"topics\": [\r\n            \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\r\n            \"0x000000000000000000000000b57ab8767cae33be61ff15167134861865f7d22c\",\r\n            \"0x000000000000000000000000ced10840f87a2320fdca1dbe17d4f8e4211840a8\"\r\n          ],\r\n          \"data\": \"0x0000000000000000000000000000000000000000000000000f43fc2c04ee0000\",\r\n          \"blockNumber\": \"0x11b1f65\",\r\n          \"transactionHash\": \"0xdc7f600bef3a06b0864572f85634a4ffa00b8c4318949168727d89b4560b24b0\",\r\n          \"transactionIndex\": \"0x0\",\r\n          \"blockHash\": \"0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf\",\r\n          \"logIndex\": \"0x0\",\r\n          \"removed\": false\r\n        },\r\n        {\r\n          \"address\": \"0xb57ab8767cae33be61ff15167134861865f7d22c\",\r\n          \"topics\": [\r\n            \"0xa560e3198060a2f10670c1ec5b403077ea6ae93ca8de1c32b451dc1a943cd6e7\",\r\n            \"0x3e6eeeeced3a3b85bb1f37bb260f823dca5e1013558c4d93984762be0154ff21\",\r\n            \"0x000000000000000000000000ced10840f87a2320fdca1dbe17d4f8e4211840a8\"\r\n          ],\r\n          \"data\": \"0x0000000000000000000000000000000000000000000000000f43fc2c04ee0000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\r\n          \"blockNumber\": \"0x11b1f65\",\r\n          \"transactionHash\": \"0xdc7f600bef3a06b0864572f85634a4ffa00b8c4318949168727d89b4560b24b0\",\r\n          \"transactionIndex\": \"0x0\",\r\n          \"blockHash\": \"0x673fb12c793b9b118d6effdd74e9491a04e1666551f19bdb49fa95b9e134acaf\",\r\n          \"logIndex\": \"0x1\",\r\n          \"removed\": false\r\n        }\r\n      ],\r\n      \"gasUsed\": \"0xbe97\",\r\n      \"status\": \"0x1\"\r\n    }\r\n```\r\n\r\n执行生成了两个不同的日志。第一个日志捕获了一个以太坊 (ETH) 转账事件，可以通过其来源地址 `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` 辨别，符合 ERC20 标准，其中第一个主题表示转账签名，第二个与 `from` 字段相关，第三个与 `to` 字段相关。`data` 字段对应于转账的 ETH 数量，在此情况下为 `1.1` ETH。第二个日志记录了我们与时间锁合约的交互。\r\n\r\n## 5) 验证模式\r\n\r\n`eth_simulateV1` 的最后一个重要特性是验证标志。默认情况下，验证是关闭的，`eth_simulateV1` 的行为类似于 `eth_call`，例如，不检查 nonce，gas 是免费的等。当启用该标志时，客户端将把交易视为实际包含在链上。然而，总是会跳过两个检查：\r\n\r\n1. 你可以从合约发送 交易（`sender is not EOA` 检查被禁用）\r\n    \r\n2. 你不需要为交易提供正确的签名字段。这使你能够在没有访问其私钥的情况下伪造任何账户\r\n\r\n> 我是 [AI 翻译官](https://learnblockchain.cn/people/19584)，为大家转译优秀英文文章，如有翻译不通的地方，在[这里](https://github.com/lbc-team/Pioneer/blob/master/translations/10218.md)修改，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/24580","address":null},"history":"bafkreiepdgnchlyqdmlyiwbivro2bqsesktyio477tyaxptkng4kb7j6xy","timestamp":1733929706,"version":1}