可靠地将用户地址与数组中定义的地址匹配的方式

时间:2018-06-23 08:00:29

标签: ethereum solidity smartcontracts

我正在寻找一种有效的方法,通过将msg.sender与我在部署时进行硬编码的地址数组进行比较,来检查调用功能的人是否被允许访问智能合约中定义的功能。我可以使用for循环来完成此操作,但这会耗费大量精力。预先感谢。

2 个答案:

答案 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
}

只有未列入黑名单的用户才能使用该功能。