我试图在solidity contract 中获取映射到特定合同(不完全(的星形名称和地址的密钥
mapping(string=>address) nameOfAccounts;
我所期待的是一个类似于Javascript中的Object.keys(nameOfAccounts)
的方法。有类似的方法吗?。或者我应该使用额外的CCD_ 2。额外的阵列可能会导致额外的气体成本(这不是我喜欢的选项(。请分享一些见解
我想知道如果不能获得钥匙,我是否还有其他方法可以做?
简单回答:如果合同没有提供映射的对象密钥列表,你就无法获得它。
长答案:
但由于区块链是一个公共的东西,你可以得到任何东西。要获得地图的所有密钥,您需要这样做:
- 设置存档节点并启用跟踪(您需要9 TB的磁盘,带有SSD缓存(
- 获取对合约的所有调用的跟踪,并搜索
SSTORE
操作码(指令( - SSTORE指令从堆栈中弹出两个参数,
Loc
(位置(和Val(值(。地点是你要找的钥匙
如果您没有存档节点的预算,您可以尝试Etherscan的API
SO上有关于如何读取合同存储的答案,可能会很有用。
还有另一个选项,反编译合同,并检查其输入,输入将具有密钥,然后扫描该合同的所有交易,并通过处理输入提取密钥(输入是tx.Data((字段(。如果你对合同有一些了解,或者如果你有消息来源,这个选项会更容易,这将是最简单的事情(处理输入(
StateDB对象类型中还有一个名为ForEachStorage()
的函数。它没有来自RPCapi的前端,但只要付出一点努力,您就可以实现自己的RPC函数来访问它,并将其放在Full节点上。这个函数接受契约的地址和一个闭包函数,它将遍历整个契约的存储。来源:https://github.com/ethereum/go-ethereum/blob/0a3993c558616868e35f9730e92c704ac16ee437/core/state/statedb.go#L634你唯一需要知道的是密钥是如何构建的,而这只能从合同来源中知道。
迭代键的最佳方法是,当添加键时,还会发出Solidity事件。
您可以从事件日志中获取密钥。这可以在客户端(JavaScript、Python(完成,但不能在Solidity内部完成,因为EVM无法访问事件数据。
在执行受限的环境中,由于效率的原因,Solidity/EVM不存储可迭代键。
点击此处了解更多信息。
尝试在Solidity中使用Goodmapping.sol而不是原始映射。
https://github.com/lidangzzz/GoodMapping.sol
这里有一个快速的例子:
// Import map uint256 => address
import "goodmapping/contracts/Map_UA.sol";
// A mapping uint256 => address
Map_UA private my_map;
// insert some key-value pare
my_map.set(0x123,1);
my_map.set(0x234,2);
// get all keys
address[] memory keys = my_map.keys();
// iterate each key-value pare
for (uint256 index = 0; index < keys.length; index++)
{
//get value
bool bExist = false;
uint256 value = 0;
(bExist, value) = my_map.get(keys[index]);
}
获取映射变量键的最简单方法是使用SmartMuv工具。该工具提供了映射键及其值的列表,您可以使用它。