获取 Solidity 映射的密钥

Get Keys of Solidity mapping

我试图在 solidity 合约中获取映射到特定合约(不完全)的明星名称和地址的键

mapping(string=>address) nameOfAccounts;

我期待的是像 Javascript 中的 Object.keys(nameOfAccounts) 这样的方法。有没有类似的方法?或者我应该使用额外的 array。额外的 Array 可能会导致额外的 gas 成本(这不是我喜欢的选项)。请分享一些见解

我想知道如果无法获取密钥,我是否可以使用其他方法?

简答:如果合约没有提供地图的对象键列表,则无法获取。

长答案:

但由于区块链是 public 东西,你可以得到任何东西。 要获取地图的所有键,您需要这样做:

  • 设置存档节点并启用跟踪(您将需要 9 TB 磁盘,带 SSD 缓存)
  • 获取对您合约的所有调用的痕迹并搜索 SSTORE 操作码(指令)
  • SSTORE 指令从堆栈中弹出 2 个参数,Loc(位置)和 Val(值)。该位置是您要查找的关键。

如果您没有归档节点的预算,可以尝试 Etherscan 的 API

SO 上有关于如何读取合约存储的答案,可能会有用。

还有一个办法,反编译合约,检查它的输入,输入会有key,然后扫描那个合约的所有交易,通过处理input提取key(输入是tx.Data() 字段)。如果您对合同有一些了解,或者如果您有资源,这个选项会更容易,这将是最简单的事情(处理输入)

StateDB 对象类型中还有一个名为 ForEachStorage() 的函数。它没有来自 RPC api 的前端,但通过一些努力,您可以实现自己的 RPC 函数来访问它并将其放在完整节点上。这个函数接受合约的地址和一个闭包函数,它会遍历整个合约的存储。资料来源:https://github.com/ethereum/go-ethereum/blob/0a3993c558616868e35f9730e92c704ac16ee437/core/state/statedb.go#L634 您唯一需要知道的是密钥是如何构建的,而这只能从合同来源中获知。

遍历键的最佳方法是,添加键时您还会发出 Solidity 事件。

您从事件日志中获取密钥。这可以在客户端(JavaScript、Python)完成,但不能在 Solidity 内部完成,因为 EVM 无法访问事件数据。

Solidity/EVM 由于执行受限环境中的效率原因,不存储可迭代键。

More information here.