获取 Solidity 映射的键

Moh*_*hiq 7 blockchain ethereum solidity smartcontracts

我试图获取映射到 Solidity 合约中特定合约(不完全是)的恒星名称和地址的密钥

mapping(string=>address) nameOfAccounts;
Run Code Online (Sandbox Code Playgroud)

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

我想知道如果无法获取钥匙,我是否可以采取另一种方法?

Nul*_*lik 8

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

长答案:

但由于区块链是公共的东西,所以你可以获得任何东西。要获取地图的所有键,您需要执行以下操作:

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

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

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

还有另一种选择,反编译合约,并检查其输入,输入将具有密钥,然后扫描该合约的所有交易,并通过处理输入(输入是 tx.Data() 字段)来提取密钥。如果您对合同有一些了解,或者如果您有来源,那么此选项会更容易,这将是最简单的事情(处理输入)

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

  • 9 TB 带 SSD 缓存?你不是说..让我们都卖掉我们的肝脏来迭代映射为什么我们不..只做mapping.keys()然后迭代它怎么样? (4认同)

Mik*_*maa 3

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

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

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

更多信息请参见此处