我们始终建议在开发Solidity智能合约时尽量不要使用汇编。但在少数情况下可能并没有其他选择,因此还是需要学习一些Solidity汇编开发的知识。在这个教程中,我们将学习如何在Solidity汇编开发中使用动态字节数组。

用自己熟悉的语言学习 以太坊DApp开发
Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、使用Remix编辑器

首先,让我们将这个简单的合约粘贴到remix编辑器中:

pragma solidity ^0.5.10;contract AssemblyArrays {bytes testArray;function getLength() public view returns (uint256) {return testArray.length;}function getElement(uint256 index) public view returns (bytes1) {return testArray[index];}function pushElement(bytes1 value) public {testArray.push(value);}function updateElement(bytes1 value, uint256 index) public {testArray[index] = value;}
}

首先熟悉一下Remix编辑器。我们首先需要选择编译器版本,然后编译合约、部署合约,执行一些功能,然后调试。

2、第一行汇编代码

现在,让我们修改getLength函数来编写第一行汇编代码:

function getLength() public view returns (uint256) {bytes memory memoryTestArray = testArray;uint256 result;assembly {result := mload(memoryTestArray)}return result;
}

上面几行代码中发生了很多事情。汇编就是这样,要实现一个非常简单的功能也需要很多代码。我们将testArray从存储复制到内存,因为这是本文的重点。以后我们可以再谈一谈存储插槽。

在深入探讨汇编语言块之前,请注意汇编指令是对32字节的字进行操作。因此,mload指令会将
memoryTestArray指向的内存位置的32个字节压入栈。。

3、Solidity汇编代码的断点设置与单步执行

现在调试一下。在Remix中,你可以通过单击行号来设置一个断点。让我们在第11行上设置一个断点,所以它看起来像这样:

更新getLength功能后,请确保已再次编译并重新部署了合约。现在,让我们调用pushElement函数将字节0x05插入数组,然后调用getLength,该函数应返回1。

调用getLength后我们可以对其进行调试。在底部面板的最后一个调用中单击“调试”按钮,这将在左侧栏中打开调试器。有一个用于快进的按钮(如:fast_forward:),它跳到下一个断点。让我们单击那个。如果你使用不同的编译器或不同的设置,那么对于你来说可能并不完全相同,但是其核心将是相同的。基本的思路是在mload执行之前获取调试器,在我的环境中是#0871指令。

4、查看Solidity汇编代码对栈的影响

现在让我们看一下调试器侧栏的栈/stack内容:

在堆栈顶部,位置0处为0x0…80。这是在内存中memoryTestArray的位置,该位置将作为mload指令的参数。

5、查看Solidity汇编代码对内存的影响

现在,让我们看一下调试器侧边栏的“ 内存”部分,从地址0x0…80开始:

这里有31个字节0x00,后跟1个字节0x01,然后是1个字节0x05,后跟31个字节0x00。这可能有点令人困惑,所以让我们退后一点,注意1个字节(8位)由2个十六进制数字表示(1个十六进制数字表示4位)。同样,0x10十六进制的十进制等于16。因此,在内存中,位置0x80保存16个字节,位置0x90(0x80+ 0x10)保存随后的16个字节,然后位置0xa0(0x90+ 0x10)保存以下16个字节,而位置0xb0保存最后的16个字节。因为汇编中的指令以32字节为单位操作,所以如果我们调用mload(0x80),它将从内存位置0x80开始取32字节放入栈。

6、单步执行mload指令

让我们看看实际执行情况。让我们单击调试器中的“单步进入”按钮(即向下的箭头)来执行mload指令。现在看一下栈顶:

mload指令取栈顶内容:0x0…80,然后将内存中位置0x0…1的32个字节压入,这是了解内存中的字节数组最重要的一点:前32个字节存储数组的长度。

尝试调用pushElement函数将元素0x06插入数组。然后调用getLength并再次调试。同样,mload将从内存位置0x80开始载入32个字节,但是这次内存的内容为0x0…2。当我们追加新元素时,Solidity为我们更新了数组的大小。

内存中发生变化的另一件事是,现在位置0xa0是0x050600…00。因此,在内存中,一个字节数组变量在前32个字节存储其长度,然后开始存储具体的成员。首先我们压入0x05,然后又压入0x06。

7、用Solidity汇编重写getLength方法

尝试再压入一些元素,调用getLength并调试,以查看内存中的新字节。如果我们将getElement 转换为汇编,这个过程将变得更加清晰:

function getElement(uint256 index) public view returns (bytes1) {uint256 length = getLength();require(index < length);bytes memory memoryTestArray = testArray;bytes1 result;assembly {let wordIndex := div(index, 32)let initialElement := add(memoryTestArray, 32)let resultWord := mload(add(initialElement, mul(wordIndex, 32)))let indexInWord := mod(index, 32)result := shl(mul(indexInWord, 8), resultWord)}return result;
}

好吧,这可能有点吓到你了!让我们​​慢慢地捋一下。

第一件超级重要的事情是,我们添加了require语句来检查index并没有超出范围。这在调用mload时是至关重要的,我们需要确保要载入的内存位置是正确的,否则可能就会泄漏调用者不应该访问的信息,这可能会让我们的合约存在严重的受攻击风险。

接下来,让我们看一下汇编代码块。由于mload一次读取32个字节,因此仅读取1个字节并不容易。如果我们把index除以32并取整,这将得到要查找的成员所在的32字节的序号。例如:

div(0, 32) = 0
div(18, 32) = 0
div(32, 32) = 1
div(65, 32) = 2

看起来还不错。但是请记住,内存中memoryTestArray指向的内置的第一个字(32字节)是存储数组长度的。因此,我们需要加上32个字节来查找第一个数组成员。考虑到所有这些因素后,我们就可以载入包含我们需要的1个字节的字(32字节):

memoryTestArray的内存位置加上32个字节以跳过数组长度,再加wordIndex上乘以32,因为每个字都有32个字节。

但是还没有完成。现在我们需要从这个字中恰好提取1个字节。为此,我们需要在字中找到该字节的索引。这是字索引除以32的余数部分,可以通过mod指令获得。例如:

mod(0, 32) = 0
mod(18, 32) = 18
mod(32, 32) = 0
mod(65, 32) = 1

不错,下面让我们完成最后一步,提取该字节。为了让字节在最前面,我们向左移动需要的位数。shl指令一次移动一位,所以为了移动指定的位数,我们要把indexInWord乘以8。

一旦我们将以这个字节开头的32个字节的字赋值给result变量,它就会删除所有其他字节,因为
我们将其类型声明为bytes1


原文链接:Solidity汇编开发之动态数组 — 汇智网

Solidity动态数组汇编开发教程相关推荐

  1. YonBuilder移动开发(APICloud)应用动态权限功能开发教程

    背景概述 当前用户个人隐私信息泄漏的问题已经越来越严重了,这种现象导致国内外对于用户隐私的保护越来越重视.在移动端的应用开发领域,如果你的应用程序未使用动态权限方式去获取用户的隐私权限,你的应用将无法 ...

  2. 以太坊EVM动态数组越界导致OOM分析

    solidity 动态数组原理分析 solidity 和Python ,JavaScript 一样,支持动态数组.我们知道,在Python 和JavaScript 里,动态数组内部的对象(比如:Len ...

  3. 发布《Win32Asm与RadAsm开发教程》全视频系列的第一阶段。

    原来的初衷是想编写<Radasm与win32汇编开发教程>第三版的,但是现实没这么多的时间去整理和编写文档教程.所以就设想直接录制视频教程.因为视频教程直观而且可以直接展示代码和操作步骤给 ...

  4. Android开发教程JAVA基础(汇总)

    Android游戏开发视频教程(汇总) Android开发教程JAVA基础之Java 概述 Android开发教程JAVA基础之标示符.关键字1 Android开发教程JAVA基础之标示符.关键字2 ...

  5. 汇编 div_Solidity汇编开发简明教程

    在用Solidity开发以太坊智能合约时,使用汇编可以直接与EVM交互,降低 gas开销成本,更精细的控制智能合约的行为,因此值得Solidity开发者学习 并加以利用.本文是Solidity汇编开发 ...

  6. android 加载三方so的方法_Android开发教程之动态加载so库文件的方法

    Android开发教程之动态加载so库文件的方法,我想对于静态加载 so 库文件,大家都已经很熟悉了,这里就不多说了.在 Android 开发中调用动态库文件(*.so)都是通过 jni 的方式,而静 ...

  7. 新版WIN32汇编开发环境介绍及RadAsm简明教程

    写在前面的话: 在准备做教程的时候去查资料,关于WIN32下汇编方面的,本来想找些现成的拿到教程里用下,但发现貌似只有一篇,是2005年时jhkdiy写的,而且翻来翻去发现所有图片也都失效了.所以准备 ...

  8. SAP UI5 应用开发教程之五十八 - 使用工厂方法在运行时动态创建不同类型的列表行项目控件试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  9. SAP UI5 应用开发教程之五十八 - 使用工厂方法在运行时动态创建不同类型的列表行项目控件

    本教程在之前的第 17 个步骤,学习了列表控件的使用方法: SAP UI5 应用开发教程之十七 - 聚合绑定在 UI5 复合控件中的使用 如下图所示,列表里每个行项目,都是使用同一种 SAP UI5 ...

  10. SAP UI5 应用开发教程之三十六 - 使用 Chrome 开发者工具 Elements 标签动态修改 CSS 类试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

最新文章

  1. Android必备:Android的体系结构
  2. R语言警告:Cannot compute exact p-value with ties的处理方法
  3. html中使用js将axios请求封装
  4. python将数组传入mysql_通过python将文件中的数据传输到MySQL,传到,mysql
  5. 如何在 Ubuntu Linux 中打开终端(小白教程)
  6. [Redis] redis-cli 命令总结
  7. 支付宝退款接口及反回参数
  8. error: component 'clippy' for target 'x86_64-unknown-linux-gnu' is unavailable for download 解决办法
  9. 等值面抽取技术(Iso-surfaces Extraction Technique)
  10. 2020牛客寒假算法基础集训营4 G题 音乐鉴赏(数学期望)
  11. 如何说孩子才会听,怎么听孩子才肯说
  12. Android Qcom USB Driver学习(二)
  13. win10无线投屏_win10电脑投屏要无线投屏器吗?
  14. 13天Java进阶笔记-day7-异常、线程
  15. matlab 信号生成,Matlab产生信号的方法
  16. overflow的overlay属性值
  17. 经典论文-MobileNetV3论文及实践
  18. 把Safari整个页面翻译成中文,,
  19. Linux运行java的Jar文件
  20. plt.subplot()使用方法以及参数介绍

热门文章

  1. android透明主题引起的快速点击activity触发退到桌面
  2. vb访问服务器文件,VB6打开远程服务器文件
  3. 俄内政部悬赏破解 Tor 匿名网络
  4. 俄罗斯一法院对谷歌处以72亿卢布罚款
  5. 数据库设计多表关系、范式
  6. echarts 地图显示(定位图标)
  7. 聚搜-聚合搜索引擎网页模板
  8. 麒麟V10系统-系统激活点击按钮无响应
  9. 解决pymysql.err.InternalError: (1054, Unknown column '某某某' in 'field list') 的问题
  10. 致敬赵雷:基于TensorFlow让机器生成赵雷曲风的歌词