028-86922220

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

solidity变量位置怎么理解

本篇内容主要讲解“solidity变量位置怎么理解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“solidity变量位置怎么理解”吧!

创新互联是一家专业提供盘山企业网站建设,专注与成都网站制作、网站建设、外贸网站建设HTML5、小程序制作等业务。10年已为盘山众多企业、政府机构等服务。创新互联专业网站制作公司优惠进行中。

1、以太坊虚拟机

在开始探讨Solidity的数据存储之前,我想先介绍下以太坊虚拟机的一些相关内容,以便更容易理解后续的部分。

EVM的内部结构大致如下图所示:

solidity变量位置怎么理解

当我们安装以太坊客户端时,它其中就包含了EVM这个专门用于运行智能合约的轻量级操作系统。EVM的架构基于栈机器模型,这意味着其指令集是基于栈而非寄存器来运作的。EVM操作码清单在黄皮书中有描述,具体可查阅以太坊虚拟机操作码和指令参考手册。

在EVM中指令的执行流程如下:当一个交易触发智能合约代码的执行时,就会实例化一个EVM,EVM的ROM载入了要调用的合约代码。程序计数器被清零,存储从合约账号对应的部分载入,内存清零,设置区块和环境变量,然后代码开始执行。

2、Solidity变量的数据存储位置

现在让我们回到memory关键字。从0.5.0版本开始,所有的复杂类型必须显式指定其存储的数据位置,有三种可选的数据位置:memory、storage和calldata。

注意:唯一可以省略数据位置声明的是状态变量,因为状态变量始终保存在账号的存储中。

storage/存储

memory/内存

calldata/调用数据

3、Solidity数据位置与赋值成本的研究

如果你不期望合约代码出现不可预计的行为,重要的一点是理解数据位置的赋值是如何运作的。

下面列出了不同位置的变量间赋值的一些规则:

下面让我们用remix debugger深入研究一下:

// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.7.0;

contract DataLocationTest {
    
    uint[] stateVar = [1,4,5];
    
    function foo() public{
        // case 1 : from storage to memory
        uint[] memory y = stateVar; // copy the content of stateVar to y
        
        // case 2 : from memory to storage
        y[0] = 12;
        y[1] = 20;
        y[2] = 24;
        
        stateVar = y; // copy the content of y to stateVar
        
        // case 3 : from storage to storage
        uint[] storage z = stateVar; // z is a pointer to stateVar
        
        z[0] = 38;
        z[1] = 89;
        z[2] = 72;
    }
    
}

用上面的代码创建一个新文件,然后部署合约。现在试着调用函数,你将会在控制台看到交易的详细信息以及旁边的debug按钮。点击这个按钮:

solidity变量位置怎么理解

这时应当可以看到调试器区域大致如下:

solidity变量位置怎么理解

点击上图中红色标识的箭头,单步执行代码。

你应当注意到的第一件事,是存储载入了stateVar的内容,这正如我们之前在EVM部分提到的,当然,这里没有局部变量。

当你继续单步执行时,你应当会看到变量y出现在局部变量区域(Solidity Locals)。继续单步执行,你还会看到需要执行很多字节码来创建必要的内存空间、从存储中载入所有数据并将其拷贝到内存。这意味着需要支付更多的gas,因此从存储区域到内存区域的赋值非常昂贵。

现在让我们研究下第二种情况:从内存区域赋值给存储区域。例如当你修改完内存变量后,可能需要将修改存回存储区域。这时也会消耗许多gas。如果我们计算debugger中单步执行前后的剩余gas差,可以看到消耗了17083 gas。该操作用了4个SSTORE指令:第一个用于保存数组大小,消耗800gas,其他三个用于更新数组的值,每个消耗5000gas。

接下来让我们看看第三种情况:从存储区域赋值给存储区域。这一次会创建一个新的局部变量来保存stateVar的值。如果我们查看代码的执行过程,就会注意到Solidity做的就是将第一个存储槽位的地址推入栈,该槽位保存有数组长度。根据文档说明,对动态数组而言,槽的位置包含了数组的长度。

如果我们比较不同情况下将数据拷贝进内存的成本,那么根据上述情况(更新并拷贝回存储:21629 gas,创建引用并直接更新状态:5085gas),非常清楚的是第二种方案的成本要低得多。

但是如果我们要直接更新状态变量,例如:

stateVar[0] = 12;

这也是可行的,不过如果你要处理映射和嵌套的数据类型,使用存储指针会让代码可读性更强。

到此,相信大家对“solidity变量位置怎么理解”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!


分享文章:solidity变量位置怎么理解
网站路径:http://www.tsicrk.com/article/igpijg.html

其他资讯

让你的专属顾问为你服务

0.9246s