欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  互联网

蜜罐合约-老版本solidity引用类型的一个坑

程序员文章站 2022-06-26 13:36:56
都是引用类型不赋初值惹的祸一个例子:注意看变量a的初始值为0:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mw28AUWa-1596979218126)(http://xwjpics.gumptlu.work/qiniu_picGo/20200809195043.png)]当调用f()函数后:a的值居然变成了1,而且多次调用f函数会发现每次a的值都会增加1。这也太坑了!原因在于:创建数组x的操作uint[] x没有添加初始的值,所以x保存的地址指向是默认指...

都是引用类型不赋初值惹的祸

一个例子:

注意看变量a的初始值为0:

蜜罐合约-老版本solidity引用类型的一个坑

当调用f()函数后:

蜜罐合约-老版本solidity引用类型的一个坑

a的值居然变成了1,而且多次调用f函数会发现每次a的值都会增加1。

这也太坑了!

原因在于:创建数组x的操作uint[] x没有添加初始的值,所以x保存的地址指向是默认指向整个合约的开始位置,也就是变量a的位置/地址。而Solidity中数组的机制是会使用初始的位置保存整个数组的长度值,而数组的值则是用这个长度和下标哈希映射到某个地方存储。**这个记录数组长度的位置就是a变量的位置,a等同于在记录局部数组x的长度!**所以当使用push操作的时候,数组的长度变为1,那么a的值也就变成了1。

解决方法:

蜜罐合约-老版本solidity引用类型的一个坑

真实案例 - 蜜罐合约

猜数游戏:猜中了就双倍返回金额,GuessHistory用来记录每次猜的信息

合约内容:

pragma solidity >=0.4.0;

contract A{
    uint public luckNum = 52;
    struct Guess{
        address player;
        uint num;
    }
    Guess[] public guessHistory;
    
    function guess(uint _num) public payable{
        Guess newGuess;
        newGuess.player = msg.sender;
        newGuess.num = _num;
        guessHistory.push(newGuess);
        if(_num == luckNum){
            msg.sender.transfer(msg.value * 2);
        }
    }
    
}

因为以太坊上的合约的内容都是可见的,所以luckNum别人是可以直接看到的,并且在这例子中还设置了public更加方便知道数字了。(这不*吗?我还能猜不中?)

猜52,下注10ether

蜜罐合约-老版本solidity引用类型的一个坑

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PI0GvEUf-1596979218147)(http://xwjpics.gumptlu.work/qiniu_picGo/20200809204955.png)]

记录上也啥都没有

蜜罐合约-老版本solidity引用类型的一个坑

明明猜对了啊?为什么?

问题所在:Guess newGuess这一步

struct和上面的uint[]一样都是引用类型,这里没有给其赋初始值或者说指定到某个空间,所以这里的newGuess指针就会指向合约的开头,也就是uint public luckNum = 52;!!

再次查看luckNum的值:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rriNDYwC-1596979218153)(http://xwjpics.gumptlu.work/qiniu_picGo/20200809205315.png)]

居然变成了这样,这个数就是msg.sender地址形成的数!与num无关是因为luckNum只够存struct中的一个参数-地址

如果把结构体中的num换到第一个吗,那么就会变成怎么猜都是对的了,因为_num会修改luckNum的值,每次都猜对!把自己坑了。

把这个数复制,再猜这个数:

蜜罐合约-老版本solidity引用类型的一个坑

蜜罐合约-老版本solidity引用类型的一个坑

为啥这次luckNum不改变了呢,因为msg.sender没有改变。

但是,真实的情况下,luckNum是不会public的,所以钱没法拿回来,自以为是反而会被坑!

总结

在老版本的solidity中,局部变量引用类型要赋初值,指向某个区域!

本文地址:https://blog.csdn.net/weixin_43988498/article/details/107900500