我正在寻找一种有效的方法,通过将msg.sender与我在部署时进行硬编码的地址数组进行比较,来检查调用功能的人是否被允许访问智能合约中定义的功能。我可以使用for循环来完成此操作,但这会耗费大量精力。预先感谢。
答案 0 :(得分:0)
起初,我很想告诉你没有办法,但是后来我有了一个有趣的主意,结果效果很好! 但是请注意,这只有在您在编译时知道地址的情况下才有效。
注意::在我的实验中,我对任务做了一些修改-我将把msg.sender与列入黑名单的地址进行比较。将其更改为您的用例很简单。
实现建议功能的直观方式可能是:
pragma solidity ^0.4.18;
contract DataInStorage {
uint counter;
address[] public blackListed = [ 0x281055afc982d96fab65b3a49cac8b878184cb16, 0x6f46cf5569aefa1acc1009290c8e043747172d89 ]
function increment() public {
for (uint i=0; i<blackListed.length; i++) {
require(msg.sender != blackListed[i]);
}
counter += 1;
}
}
原来的天然气成本如下:
<number of addresses> | <gas spent>
100 | 124808
200 | 207708
因此,似乎一次迭代的成本约为829(829 * 100 = 82900 = 207708 - 124808
)
首先,为什么要迭代处理并将其与msg.sender进行比较昂贵?这不是因为loop
的原因,也不是因为if
的比较。原因是EVM需要从合同存储中读取。读取和写入存储是最昂贵的操作。
所以这个想法来了。如果我们不将这些地址放入合同存储中,而是合同代码怎么办?让我们尝试一下
pragma solidity ^0.4.18;
contract DataInCode {
uint counter;
function increment() public {
require(0x281055afc982d96fab65b3a49cac8b878184cb16 != msg.sender);
require(0x6f46cf5569aefa1acc1009290c8e043747172d89 != msg.sender);
counter += 1;
}
}
我尝试了使用更多地址的这种模式,这是一个有趣的结果
<number of addresses> | <gas spent>
100 | 45338
200 | 49038
因此,在这种情况下,一次地址验证只花了我们37瓦斯。这比合同存储的解决方案好22倍。
如果有人可以提供更多的技术解释,为什么在EVM中加载代码比加载数据存储便宜得多,我很想听听。
代码中的数据(100个地址)https://ethfiddle.com/mDB9OM2azy
数据输入代码(200个地址)https://ethfiddle.com/nIt2QwBLTX
存储中的数据(100个地址)https://ethfiddle.com/Wg5CMAN0OU
存储中的数据(200个地址)https://ethfiddle.com/5NVVCVUT0R
经过松露测试
答案 1 :(得分:0)
使用映射来存储它。
mapping(address => bool) public blacklisted;
...
require(!_blacklisted[msg.sender]);
您也可以将其用作修饰符:
modifier notBlacklisted() {
require(!blacklisted[msg.sender]);
_;
}
然后使用函数:
function foo() notBlacklisted public
{
// do stuff
}
只有未列入黑名单的用户才能使用该功能。