玩以太坊链上项目的必备技能(内联汇编 [inline assembly]-Solidity之旅十八)

news2024/10/7 20:05:40

概要

大抵是讲到汇编,身为编程开发者的我们脑瓜子早就嗡嗡作响了。看那晦涩难懂的低级汇编代码,敢断言,那一行不是我写的,其他行也不是我写的。

自从C语言问世,而后类C语言犹如雨后春笋般地搅动着IT界,而这些语言有别于汇编语言那样。它们就是更贴切自然语言的高级编程语言,可这些高级编程语言最终还是要编译成机器语言(汇编语言)。

EVM(Ethereum Virtual Machine)是一种栈(Stack)结构,我们知道是一种先进后出(LIFO)的数据结构。

那为什么要用汇编来编写呢?

借您所问,既然 Solidity 可以编写出优秀的智能合约,那为什么还要使用低级地汇编语言呢?

在回答这个问题之前,我们来看看每个新的编程语言诞生都是为了解决当前编程语言无法解决,或者说使用当前编程语言解决起来比较麻烦,那么,新的编程语言就在这样的环境下应运而生,当然咯,并不是所有新编程语言都是为了解决当前编程语言不能解决的问题,才被开发出来,而是……(此处不便说出缘由,毕竟它也不是本文的重点)。

细粒度控制

Assembly允许您执行一些仅仅靠 Solidity 无法实现的逻辑,比如,指向特定的内存插槽(Memory Slot)

当我们在编写库(library)时,细粒度控制特别有用,因为它们会被重复使用。

节省 gas

在 Solidity 中使用 Assembly 的主要好处之一是节省 gas。 让我们尝试通过创建一个将 2 个值 x 和 y 相加并返回结果的函数来比较 Solidity 和 Assembly 之间的 gas 成本。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract AssemblyExample {
    
    function addAssembly(uint x, uint y) public pure returns (uint) {
        assembly {
            let result := add(x, y)
            mstore(0x0, result)
            return(0x0, 32)
        }
    }
 
    function addSolidity(uint x, uint y) public pure returns (uint) {
        return x + y;
    }
  
}

在这里插入图片描述

Solidity 中两种方式实现 Assembly

  • 1、 内联汇编:也可以在 Solidity 代码中使用。
  • 2、 独立程序集:无需编写 Solidity 代码即可使用。

怎么使用 Assembly?

正如上面的例子那样,汇编代码运行在assembly { ...}汇编块中的。

汇编代码是使用YUL语言来编写的!

内联汇编块不共享命名空间,即不能在一个汇编块调用另一个汇编块中定义的变量。

assembly {
   // some assembly code here
}

在这里插入图片描述

以下是一个简单的示例,函数接受两个参数,并将它们的和作为返回值,看看使用 Assembly是怎么实现的?了解它们在 EVM的工作方式。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract AssemblyExample {
    
   function addition(uint x, uint y) public pure returns (uint) {
     
    assembly {
        
        //声明一个 result 变量,并将 x,y之和赋值给它
        let result := add(x, y)   // x + y
        
        //使用 mstore 操作码将 result存在 memory 中,地址是 0x0
        mstore(0x0, result)       // store result in memory
         
        //返回 32 字节的 memory 地址
        return(0x0, 32)          
        
    }
}
  
}

在这里插入图片描述

数据存储

让我们来看看一个简单的例子。我们将数据存放在storage(存储)中,然后再去调用它。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract StorageDataExample {

    function setData(uint256 newValue) public {
        assembly {
            sstore(0, newValue)
        }
    }

    function getData() public view returns(uint256) {
        assembly {
            let v := sload(0)
            mstore(0x80, v)
            return(0x80, 32)
        }
    }
}

在这里插入图片描述

setData函数使用了sstore操作码将变量newValue写入storage(存储)中。

getData函数先是用了sload操作码来加载storage(存储)中的数据,它并不能从storage中直接返回。所以才需要mstore操作码将其写入memory(内存)中,最后我们返回引用memory(内存)中存放数据的地址和 32 字节长度的数据。

https://docs.soliditylang.org/en/latest/yul.html

指令解释
stop()-F停止执行,与return(0, 0)相同
add(x, y)Fx + y
sub(x, y)Fx - y
mul(x, y)Fx * y
div(x, y)Fx / y 或 如果 y == 0,则为 0
sdiv(x, y)Fx / y,对于有符号的二进制补数,如果 y == 0,则为 0
mod(x, y)Fx % y, 如果 y == 0,则为 0
smod(x, y)Fx % y, 对于有符号的二进制补数, 如果 y == 0,则为 0
exp(x, y)Fx的y次方
not(x)Fx的位 “非”(x的每一个位都被否定)
lt(x, y)F如果 x < y,则为1,否则为0
gt(x, y)F如果 x > y,则为1,否则为0
slt(x, y)F如果 x < y,则为1,否则为0,适用于有符号的二进制数
sgt(x, y)F如果 x > y,则为1,否则为0,适用于有符号的二进制补数
eq(x, y)F如果 x == y,则为1,否则为0
iszero(x)F如果 x == 0,则为1,否则为0
and(x, y)Fx 和 y 的按位 “与”
or(x, y)Fx 和 y 的按位 “或”
xor(x, y)Fx 和 y 的按位 “异或”
byte(n, x)Fx的第n个字节,其中最重要的字节是第0个字节
shl(x, y)C将 y 逻辑左移 x 位
shr(x, y)C将 y 逻辑右移 x 位
sar(x, y)C将 y 算术右移 x 位
addmod(x, y, m)F(x + y) % m,采用任意精度算术,如果m == 0则为0
mulmod(x, y, m)F(x * y) % m,采用任意精度算术,如果m == 0则为0
signextend(i, x)F从第 (i*8+7) 位开始进行符号扩展,从最低符号位开始计算
keccak256(p, n)Fkeccak(mem[p…(p+n)))
pc()F代码中的当前位置
pop(x)-F丢弃值 x
mload§Fmem[p…(p+32))
mstore(p, v)-Fmem[p…(p+32)) := v
mstore8(p, v)-Fmem[p] := v & 0xff ((只修改了一个字节))
sload§Fstorage[p]
sstore(p, v)-Fstorage[p] := v
msize()F内存的大小,即最大的访问内存索引
gas()F仍可以执行的气体值
address()F当前合约/执行环境的地址
balance(a)F地址为A的余额,以wei为单位
selfbalance()I相当于balance(address()),但更便宜
caller()F消息调用者(不包括 delegatecall 调用)。
callvalue()F与当前调用一起发送的wei的数量
calldataload§F从位置p开始的调用数据(32字节)
calldatasize()F调用数据的大小,以字节为单位
calldatacopy(t, f, s)-F从位置f的calldata复制s字节到位置t的内存中
codesize()F当前合约/执行环境的代码大小
codecopy(t, f, s)-F从位置f的code中复制s字节到位置t的内存中
extcodesize(a)F地址为a的代码的大小
extcodecopy(a, t, f, s)-F像codecopy(t, f, s)一样,但在地址a处取代码
returndatasize()B最后返回数据的大小
returndatacopy(t, f, s)-B从位置f的returndata复制s字节到位置t的内存中
extcodehash(a)C地址a的代码哈希值
create(v, p, n)F用代码mem[p…(p+n))创建新的合约,发送v数量的wei并返回新地址; 错误时返回0
create2(v, p, n, s)C在keccak256(0xff . this . s . keccak256(mem[p…(p+n)))地址处 创建代码为mem[p…(p+n)]的新合约 并发送v 数量个wei和返回新地址, 其中 0xff 是一个1字节的值, this 是当前合约的地址, 是一个20字节的值, s 是一个256位的大端的值; 错误时返回0
call(g, a, v, in, insize, out, outsize)F调用地址 a 上的合约,以 mem[in…(in+insize)) 作为输入 一并发送 g 数量的 gas 和 v 数量的 wei, 以 mem[out…(out+outsize)) 作为输出空间。 若错误,返回 0 (比如,gas 用光) 若成功,返回 1
callcode(g, a, v, in, insize, out, outsize)F相当于 call 但仅仅使用地址 a 上的代码, 执行时留在当前合约的上下文当中
delegatecall(g, a, in, insize, out, outsize)H相当于 callcode, 但同时保留 callercallvalue
staticcall(g, a, in, insize, out, outsize)B相当于 call(g, a, 0, in, insize, out, outsize) 但不允许状态变量的修改
return(p, s)-F终止执行,返回 mem[p…(p+s)) 上的数据
revert(p, s)-B终止执行,恢复状态变更,返回 mem[p…(p+s)) 上的数据
selfdestruct(a)-F终止执行,销毁当前合约,并且将余额发送到地址 a
invalid()-F以无效指令终止执行
log0(p, s)-F用 mem[p…(p+s)] 上的数据产生日志,但没有 topic
log1(p, s, t1)-F用 mem[p…(p+s)] 上的数据和 topic t1 产生日志
log2(p, s, t1, t2)-F用 mem[p…(p+s)] 上的数据和 topic t1,t2 产生日志
log3(p, s, t1, t2, t3)-F用 mem[p…(p+s)] 上的数据和 topic t1,t2,t3 产生日志
log4(p, s, t1, t2, t3, t4)-F用 mem[p…(p+s)] 上的数据和 topic t1,t2,t3,t4 产生日志
chainid()I执行链的ID(EIP-1344)
basefee()L当前区块的基本费用(EIP-3198和EIP-1559)
origin()F交易发送者
gasprice()F交易的气体价格n
blockhash(b)F区块编号b的哈希值–只针对最近的256个区块,不包括当前区块。
coinbase()F目前的挖矿的受益者
timestamp()F自 epoch 开始的,当前块的时间戳,以秒为单位
number()F当前区块号
difficulty()F当前区块的难度
gaslimit()F当前区块的区块 gas 限制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/125172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【金猿人物展】实在智能创始人、CEO孙林君:我们为什么坚定在IPA方向努力?...

‍孙林君本文由实在智能创始人、CEO孙林君撰写并投递参与“数据猿年度金猿策划活动——2022大数据产业趋势人物榜单及奖项”评选。‍数据智能产业创新服务媒体——聚焦数智 改变商业充满“不确定性”的2022年即将过去&#xff0c;不确定性带来的不仅是挑战&#xff0c;还有新机…

安装 Azure CL 并生成 service principal 文件

1 安装 1.1 Yum⽅式安装 For Linux distributions with yum such as RHEL, Fedora, or CentOS, theres a package for the Azure CLI. This package has been tested with RHEL 7, Fedora 19 and higher, and CentOS 7. sudo rpm --import https://packages.microsoft.com/k…

【nowcoder】笔试强训Day11

目录 一、选择题 二、编程题 2.1最近公共祖先 2.2求最大连续bit数 一、选择题 1.下面哪个标识符是合法的&#xff1f; A. 9HelloWorld B. _Hello World C. Hello*World D. Hello$World java标识符的命名规则应以字母、下划线、美元符开头&#xff0c;后跟字母、下划线…

python实战案例——采集二手车数据并分析其价值

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 环境使用: Python 3.8 Pycharm 专业版是付费的 <激活码可以免费用> 社区版是免费的 模块使用: 第三方模块 需要安装的 requests >>> pip install requests parsel >>&…

【生成对抗网络】GAN生成对抗网络理论知识

GAN生成对抗网络目录引入GeneratorNetwork as Generator为什么要训练Generator&#xff1a;需要输出是分布引入GANBasic Idea of GAN&#xff1a;区分Unconditional generation 与 Conditional generationUnconditional generationConditional generation引入DiscriminatorGene…

基于Bert-Lstm-Crf的命名实体识别(PyTorch 实现)

1 前言 1-1 简介 命名实体识别(NER)是自然语言处理的基础任务&#xff0c;处于工程性任务的上游&#xff0c;很多的下游任务依赖于命名实体识别的效果&#xff0c;所以命名实体识别也是自然语言处理中非常重要的一环。命名实体识别的任务非常简单&#xff0c;给出一段文本&…

MindSpore模型快速调优攻略笔记分享(上)

• 近年来&#xff0c;深度学习技术在语音识别、自然语言处理、计算机视觉、信息检索等任务上取得了突破性进展; • 深度学习模型的复杂度与规模日益扩张&#xff0c;导致模型的调试调优成为了困扰算法工程师的一大难题; • MindSpore是由华为自研的深度学习框架&#xff0c;…

整理收集python面试常见题目

1.多进程和多线程 1.python多进程和多线程看这一篇就够了_T型人小付的博客-CSDN博客 2.多进程和多线程的实现&#xff1a;一文看懂Python多进程与多线程编程(工作学习面试必读) - 知乎 3.多线程的补充&#xff1a;一文看懂Python多进程与多线程编程(工作学习面试必读) - 知乎…

软件测试面试技巧 这么准备,拿下心仪offer不是问题

拥有一个心仪的offer&#xff0c;是每个软件测试工程师们都梦寐以求的事情&#xff0c;那如何才能通过最后的面试一关&#xff0c;拿到offer呢&#xff1f; 俗话说&#xff0c;知己知彼百战不殆&#xff0c;作为测试员&#xff0c;在面试前对面试官可能提出的问题进行总结和准…

UDS - 14.2.1 RoutineControl (31) service

来自&#xff1a;ISO 14229-1-2020.pdf 目录 14.2.1 服务描述 14.2.1.1 概述 14.2.1.2 通过引用routineIdentifier来启动一个例程 14.2.1.3 通过引用routineIdentifier来停止一个例程 14.2.1.4 通过引用routineIdentifier来请求例程结果 14.2.2请求消息 14.2.2.1请求消…

【从零开始学习深度学习】31. 卷积神经网络之残差网络(ResNet)介绍及其Pytorch实现

和之前介绍的批量归一化层作用类似&#xff0c;残差网络&#xff08;ResNet&#xff09;提出的主要目的也是为了优化深度神经网络中数值稳定性问题。 1. 残差块介绍 假设输入为x\boldsymbol{x}x&#xff0c;希望学出的理想映射为f(x)f(\boldsymbol{x})f(x)。下图左右为普通网…

【GO】 K8s 管理系统项目[API部分--Namespace]

K8s 管理系统项目[API部分–Namespace] 1. 接口实现 service/dataselector.go type namespaceCell corev1.Namespacefunc(n namespaceCell) GetCreation() time.Time {return n.CreationTimestamp.Time }func(n namespaceCell) GetName() string {return n.Name }2. Namespa…

景联文科技:赋能智能安防,详谈其中运用到的数据标注类型

“数据显示&#xff0c;2013-2020年我国智能安防行业市场规模由101亿元增长至511亿元。随着智能安防在多个领域的深化应用&#xff0c;预计2023年我国智能安防行业市场规模将超1000亿元。 智能安防领域中,数据标注主要应用于计算机视觉与语音识别两个主要领域&#xff0c;具体…

人口数据可视化,深圳是人口密度最高的城市,东莞上海位居二三名

进入2022年以来&#xff0c;人口问题频频引起热议&#xff0c;人口老龄化、生育意愿再创新低、男女比例失衡等等问题频出。具体的人口问题如何&#xff0c;跟随可视化互动平台的数据可视化大屏一起来了解吧&#xff01; 我国各省人口数量从地图分布图看&#xff0c;广东省、山…

安装Pytorch

太难了 之前在学校就没安装好 各种报错 终于安装好了 浅浅记录一下 撒花撒花 菜鸡经验&#xff1a; 1.本地python 与 Anaconda 是两个独立的东西 2.可直接在Anaconda中创建不同新的虚拟环境以适配不同的需求 3.cuda 的版本与 NVIDIA版本需要一致&#xff0c;与Python环境也需要…

Echarts图表相关知识

一个基于 JavaScript 的开源可视化图表库。目前我们的前端框架中已经集成了Echarts库v5.3.2&#xff09;&#xff0c;使用的时候不需要再次安装&#xff0c;直接使用即可&#xff0c;具体安装方法不再赘述。 有些时候官网的例子不满足我们的需求&#xff0c;这个时候就要求我们…

cq:fast lookup argument

1. 引言 Ariel Gabizon等人2022年论文《cq: Cached quotients for fast lookups》。 lookup argument的核心思想为&#xff1a; 对于特定的quotient多项式&#xff0c;经某种预处理之后&#xff0c;将更易于计算其commitments。 当前的lookup argument系列方案主要有&#…

实拍视频、图片素材库,高质量、免费下载。

这几个网站的实拍素材&#xff0c;质量高&#xff0c;还可以免费下载。 1、菜鸟图库 https://www.sucai999.com/?vNTYwNDUx 菜鸟图库有超多设计类素材&#xff0c;像平面、UI、电商、办公类等等在这个网站都能找到&#xff0c;网站还有很多实拍视频素材&#xff0c;质量很高&a…

k8s集群部署01

k8s集群部署01Kubernetes简介Kubernetes部署节点部署关于yum缓存提示满了&#xff0c;Rhel7换源解决报错解决过程配置文件内容—要自己看链接是否过期集群初始化Kubernetes-kubectl命令出现错误【The connection to the server localhost:8080 was refused - did you specify t…

git chrry pickup

git chrry pickup目录概述需求&#xff1a;设计思路实现思路分析1.java2.转移分支3.git merge4.cherry pick.切换到 master 分支Cherry pick 操作参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;…