耗油量过多

时间:2017-12-25 18:48:03

标签: ethereum solidity web3

我正在编写我的第一份Eth合同,我遇到了一个问题,buy方法的耗气量(估算值)真的很高(在达到“最大值”之前快速> N百万气体燃气余量超过“错误。”

要快点,想法如下: - 有一个地图(2D地图),你可以拥有多个区域(在这里称为单位,这就是为什么我保持“unitsToState”明显的映射)。 - 您可以一次购买多个相邻区域,因此会创建“块”。 - 因此,当您购买新的块时,合约必须检查内部的所有单位是否为空(unitsToState [x] == 0)。购买该块时,这些状态将设置为1.

我在这里不解释太多细节,因为我猜这个问题主要是“Solidity”糟糕的算法编程。

这种方法可以用500k左右的气体进行,从X,从Y,到X,到Y代表一个小区域,但是当它们相距很远时,我在气体估算期间得到了“超出最大气体容量”误差。真的,我觉得有问题..

```     ...

struct Block {
    address owner;
    uint fromX;
    uint fromY;
    uint toX;
    uint toY;
    string imageUrl;
    string redirectUrl;
    string text;
    bool removed;
}   

uint size = 100;
mapping (uint => uint) unitsToState;
Block[] public blocks;
uint public areaPrice;
uint public areaPerUnit;

...


function buy(uint fromX, uint fromY, uint toX, uint toY, string imageUrl, string redirectUrl, string text) payable public {
    require(fromX >= 0);
    require(fromY >= 0);
    require(fromX <= toX);
    require(fromY <= toY);
    require(toX < size);
    require(toY < size);

    // Here do check of collisions.
    for (uint i = fromX; i <= toX; i++) {
        for (uint j = fromY; j <= toY; j++) {
            require(getUnitsToState(i*size*size + j) == 0);
        }    
    }

    uint width = toX - fromX + 1;
    uint height = toY - fromY + 1;
    uint areaCount = width * height * areaPerUnit;
    uint price = areaCount * areaPrice;
    require(msg.value >= price);

    Block memory b = Block(
       msg.sender,
       fromX,
       fromY,
       toX,
       toY,
       imageUrl,
       redirectUrl,
       text,
       false
    );
    blocks.push(b);

    // Registrer units states.
    for (i = fromX; i <= toX; i++) {
        for (j = fromY; j <= toY; j++) {
            unitsToState[i*size*size + j] = 1;
        }    
    }
}

...

```

1 个答案:

答案 0 :(得分:0)

大循环,特别是嵌套循环,在Solidity中是危险的。你必须要小心你在每次迭代时执行的逻辑。

在您的情况下,它是您设置unitsToState标志的第二个循环,导致燃气使用量大幅增加。存储非零数据的每次调用都要花费20,000气体(零为5,000)。你的循环每次迭代都会产生这种代价。

看起来你拥有在Block结构中进行碰撞检查所需的一切。你能用它吗?

for (uint8 i = 0; i < blocks.length; i++) {
  Block storage bTest = blocks[i];

  bool xIntersect = int(fromX) - int(bTest.toX) <= 0 && int(toX) - int(bTest.fromX) >= 0;
  bool yIntersect = int(fromY) - int(bTest.toY) <= 0 && int(toY) - int(bTest.fromY) >= 0;

  require (!(xIntersect && yIntersect));
}

请参阅Appendix G of the yellow paper了解天然气费用。