前阵子一个小兄弟遇到个问题需要攻克,我评估了一下,认为有办法搞定;为了给他加油打气,相信我的判断,大话告他说在技术上吹过的牛我基本都实现了。今天,必须承认这个牛吹爆了。要解决的问题是:如何遍历一个以太坊合约存储里的映射?
网上数年前就有这样的问题提出。如:
– Iterating mapping types:https://forum.ethereum.org/discussion/1995/iterating-mapping-types
– How to loop through mapping in solidity?:https://ethereum.stackexchange.com/questions/12145/how-to-loop-through-mapping-in-solidity
– Soldity: Iterate through address mapping:https://stackoverflow.com/questions/48898355/soldity-iterate-through-address-mapping
还有一篇文章,是指导如何实现一个可以遍历的 map(Creating a Smart Contract having Iterable Mapping),图文并茂:https://medium.com/rayonprotocol/creating-a-smart-contract-having-iterable-mapping-9b117a461115
当然,最主要的是,要搞清楚为什么 map 是无法遍历的。以下内容来自于 https://me.tryblockchain.org/solidity-mapping.html。
映射的存储模型
由于状态变量是存储在区块链上的,所以存储空间需要预先分配,但映射的存储值是可以动态增改的,那么最终是如何支持的呢?状态实际存储时是以哈希键值对的方式。其中哈希是由键值和映射的存储槽位序号拼接后计算的哈希值(映射只占一个槽位序号),也就是说值是存到由 keccak256(k . p) 计算的哈希串里,这里的 k 表示的是映射要查找的键,p 表示映射在整个合约中相对序号位置。
这种方式,事实上就是等同于以 hash 作为 index 的空间布局,遍历就几乎不可能了。