Skip to content

solidity 上的坑

Solidity 是一种类 JavaScript 语法的运行与以太坊 EVM 上的智能合约语言,目前(v0.7.1)限制还是很大,很多业务逻辑受限于 Solidity 的蹩脚设计无法实现。

从 0.4.x 一路用到 0.7.x,也算是使用了一年多了,记忆比较深刻,比较难定位到问题的两个坑,在这里跟大家分享一下。

uint 越界

一般来说使用 OpenZeppelin 的 SafeMath 库可以避免大多数情况下的越界情况,但是在一个简单的循环中,我们可能考虑不到,比如说这种情况:

uint[10] memory aUintArray;
for (uint i = aUintArray.length - 1; i >= 0; i--) {
   do something
}

在这个情境下你是否发现了什么问题?这个循环到 0 的时候,会越界,0--,这样智能合约就会出错了。

delete 用法

delete 是个比较常用的用法,而且使用 delete 还会返还部分 Gas 费用,在 mapping 类型的数据中使用 delete 是十分正常的,比如 mapping(address => uint) _addressToID 这种,delete _addressToID(msg.sender) 会将 msg.sender 这个 key 的 value 置为目标数据类型的默认值(布尔值:false,数字:0),这也是我们期望的。

那么在数组中,delete 就显得比较奇怪了,比如说:

uint[] uintArray;

function deleteIndex(uint i) public {
   uint len = uintArray.length;
   assert(i >= 0 && i < len); // 编号 ①
   delete uintArray(i);
   assert(uintArray.length == len-1); // 编号 ②
}

你认为 编号② 是 true 还是 false ?实际上是 false ,solidity 在 delete 删除数组元素时只会将该元素位置置为数组类型的默认值,并不会改变数组长度。
文档地址:delete

delete a[x] deletes the item at index x of the array and leaves all other elements and the length of the array untouched. This especially means that it leaves a gap in the array. If you plan to remove items, a mapping is probably a better choice.

删除数组元素

如上面一个部分所述,删除数组元素时只会将该元素位置置为数组类型的默认值,并不会改变数组长度,那么我们应当如何正确的删除数组内的元素呢?

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

contract Test {
    uint[] public arr;
  
    function add(uint item) public {
        arr.push(item);
    }
  
    function remove(uint item) public {
        bool flag;
        for (uint i = 0; i < arr.length; i++) {
            if (arr[i] == item) {
                // 将要删除的元素与最后一个元素互换
                arr[i]=arr[arr.length-1];
                // 删除最后一个元素
                arr.pop();
                flag = true;
            }
        }
        if (!flag) revert("item not found");
    }
  
    function len() public view returns(uint) {
        return arr.length;
    }

}

Comments

Commenting as a guest. A nickname is required; email is optional. Only new comments posted after verifying your email and signing in will appear on your profile. Existing guest comments will not be linked automatically.

Share article

solidity 上的坑

Email X

View original ↗