此过程在智能合约的生命周期内仅执行一次。初始化代码并不会被存储在智能合约中,实际上它执行的返回值也就是字节码才会被存在智能合约中。切记,智能合约一旦被创建,任何人都无法更改其代码。...此外,还可以使用CREATE操作码来创建智能合约,这是Solidity语言新构造的编译操作码。两种智能合约创建方案有着相同的运行机制。...消息调用由调用命令触发,请求和返回值由内存传递 Solidity语言为地址类型提供了一个本地调用方法,其工作方式如下: 这里的gas就是要发送的以太坊燃料数量,address是要调用的智能合约地址,value...所有的操作都是在堆栈上执行的 通过PUSH/POP/COPY/SWAP等操作来交互 以太坊虚拟机提供了许多操作码来直接对堆栈进行操作。其中包括: POP 从堆栈中删除项目。...以太坊虚拟机提供两个操作存储的操作码: SLOAD: 将存储中的字加载到堆栈中。 SSTORE: 将一个字保存到存储中。 Solidity语言的内联汇编也支持这些操作码。
[6] 第 4 篇:结束/中止执行的 5 个指令[7] 第 5 篇:执行流 if/else/for/函数[8] 第 6 篇:完整的智能合约布局[9] 第 7 篇:外部调用和合约部署[10] 1....STOP(停止) 我们将使用 EVM 中最简单的操作码来开始。 这是唯一一个消耗 0Gas 的操作码,顾名思义,它结束智能合约的执行,不返回任何数据。...在指令 54 到 56 之间,EVM 在之前的结果(80)上加上 20,等于 a0(20=十进制的 32,因为这是一个内存插槽的大小,这里只有一个返回值)。...有 16*16=256 个不同的操作码(00 到 FF)的组合,但只有一部分被分配。(大约有 145 个没有被分配。) 已分配的操作码 这些未分配的操作码被称为:INVALID 操作码。...通常情况下,如果你用 solidity 将你的智能合约编译成 EVM 的字节码,除非在编译过程中出现错误,否则不应该有可访问的无效操作码。
最重要的是,你不需要做任何事情就可以激活 Solidity 集成的 SafeMath。只要写上a+b,就会在溢出时自动回退交易。...无效的操作码被还原取代 到目前为止,某些操作会导致 INVALID操作码的执行。这个操作码的问题是,它消耗掉所有剩余的 Gas。这显然是不好的且没必要。为什么要浪费 Gas,把它捐给矿工?...更多细节,在这里[8]查看 revert和 assert的区别。 现在 Solidity 使用revert操作码。...如何迁移到 Solidity 0.8 在大多数情况下,迁移应该是非常直接的。只有在一些情况下,你做奇怪的类型转换可能会变得更加困难。...将 x**y**z改为(x**y)**z,因为默认的执行顺序改变了。 将 byte类型改为 byte1 。 我省略了一些细节,关于完整的变更日志和所有变更的细节,请查看文档这里[10]。
为方便起见,我使用这些功能中的每一个创建了一个简单的合约,你可以在 remix[8]中对其进行测试。...在 Solidity 0.4.10 之前(以及之后的一段时间),这是强制执行权限的常见模式: contract HasAnOwner { address owner; function...尚不支持此返回值参数_,但你可以查看此_问题_[12] 以了解该更新。...将剩余 gas 退还给调用者 目前,当你的合约抛出异常时,它会耗尽所有剩余的 gas。这可能会导致对矿工的慷慨捐赠,并且最终会花费用户很多钱。...区别在于字节码输出,为此我将引用文档[13](我这里强调): 应该使用 require 函数来确保满足有效条件,例如输入或合约状态变量,或者来自外部合约调用的有效返回值。
理解它们的关系对于智能合约开发、部署和执行至关重要。以下是对这些版本关系的详细介绍:1. Solidity 版本Solidity 是以太坊平台上的主要智能合约编程语言。...EVM 的每次升级或变更都会影响其支持的操作码(opcodes)、执行行为以及与智能合约的兼容性。EVM 操作码更新:以太坊的不同升级会引入新的操作码或修改现有的操作码。...与 Solidity 的关系:Solidity 编译的合约字节码是基于 EVM 操作码集的,因此 EVM 版本更新时,新的操作码可能会在未来的 Solidity 版本中支持。...然而,如果 EVM 的某些行为或操作码发生变化,可能会影响特定智能合约的执行方式,尤其是在使用新版本 Solidity 编译的合约时。4....Spurious Dragon (2016):改进了 EVM 中的状态清理,继续对操作码和 gas 费用进行优化。
在 Solidity 中 在 Solidity 中,每当你用memory关键字实例化一个变量并赋值(bytes/字符串,或者函数的返回值),底层的 EVM 就会执行mstore指令。...Solidity 编译器的 C++源代码提供了更多信息来理解它: 来源: SemanticInformation.cpp[18] MSIZE操作码返回在当前执行环境中访问内存的最高字节偏移。...没有比evm.codes[19]对msize操作码更好的解释了,可以总结一下: msize 跟踪当前执行中曾经访问过的最高偏移量。...对于 Solidity 的代码: 这些是由 Solidity 编译器生成的操作码。...看一下内存切换,说明 "无数据可用" 正如你从上面的截图中所看到的,左侧边栏的 "Memory"字段现在显示 "无数据可用"。刚刚发生了什么? CALL操作码使 EVM 改变了执行环境。
EVM Playground 这个 EVM 操练场(EVM Playground)将有助于巩固你对这 3 个操作码的理解以及内存位置的工作原理。...点击 "运行 "和右上方的卷曲箭头,步进操作码,看看堆栈和内存是如何被改变的。(在操作码的上方有注释,描述了每一部分的作用) 当执行完上面的操作码,你可能会注意到一些奇怪的现象。...我不能不强调,使用 EVM Playground 和自己按步执行操作码是多么重要。这将大大促进你的学习。现在让我们来看看这 6 个部分。...请记住 Solidity 中内存数组中的元素总是占据 32 字节的倍数(这甚至对 bytes1[]来说也是如此,但对 bytes 和字符串来说不是如此) 数组的大小乘以 32 个字节,告诉我们需要分配多少内存...下次我们需要写一些 solidity 代码时,这将对我们有好处。当你执行一些合约操作码,看到某些内存位置不断 pop 出(0x40)时,你现在就会知道它们的确切含义。
十分绝望,整理外网上一些debug策略,帮助同样陷于缺少console.log()来debug-solidity的同学打开思路 如何更好的使用Remix调试合约? 应该在Remix中编写合同。...经典错误异常表 Wrapping over/under:经典溢出错误,Solidity 中的数字存储空间有限,使数字大于其分配的存储空间,就会溢出到最小值 OUT_OF_GAS: "out of gas...原因有很多,例如递归调用,执行过于复杂的计算,以及调用函数链那太长了。...(例如数组超出范围)时会发生此错误 INVALID_OPCODE: "invalid opcode” 试图在某个地方执行不存在的操作码 REVERT: "revert” 某处坏了。...truffle debug 交易哈希 靠他的单步执行断点调试了,虽然remix也基本可以做到类似的事情 为何事件和空白的代码行会失败?
当你调用一个智能合约时,EVM 会运行并执行其字节码中的一组指令(=操作码)。其中一些操作码指示 EVM 从/向不同的位置读写数据。EVM 需要这些多个数据位置来正确完成其工作。...作为一个 Solidity 开发者,对 EVM 中的数据位置以及如何充分使用它们的良好理解将使你能够: 提高你的智能合约的性能。 最小化其执行成本(调用其公共或内部函数时使用的 Gas 差异)。...堆栈是大多数在函数内部创建的局部变量所在的地方。它是 EVM 的一个重要部分。 在低层,可以用来对堆栈进行操作的 EVM 操作码,包括PUSH、POP、SWAP和DUP指令。...你只能在函数中的 3 个地方指定引用一个变量的数据位置。 A) 对于参数(=函数定义) B) 对于函数内部的局部变量(=函数主体) C) 返回值总是在内存中(=函数定义)。...storage的 getter 执行以下步骤。
所以,我们看到了代码是如何从函数选择器出发,进入这个包装结构,进入函数体,又从函数体出来,然后处理函数体产生的返回值,并打包这些数据返回给用户。...函数选择器应该把我们带到指令 130,也就是balanceOf的包装器,然后从那里把我们带入函数的主体,再从函数体出来,为用户打包返回值。...函数包装器是一个中介,它为函数主体使用的 calldata 进行解包,将执行路由给它,然后为用户重新打包任何返回来的数据。这个包装器结构适用于所有属于 Solidity 合约公共接口的函数。...大结构:函数选择器、包装器和函数体 正如我们在本系列的前几部分所做的那样,我们把对transfer函数的调用的调试工作留给你。...你应该看到包装器这次是如何解压两个值的-- 接收者_to地址,以及转移的_value--将其发送给函数体,然后获取函数体的响应,再打包给用户。很有意义,对吗?
注意,在使用verbatim时有一些注意事项,关于它的细节可以在文档[7]中找到。 用于新的操作码 作为一个实际的例子,我们可以用它来方便地将一个新提出的 EVM 操作码注入二进制。...以提议的BASEFEE(在0x48)操作码为例(见EIP-3198[8]和EIP-1559[9]),由于 Solidity 编译器目前不支持这个操作码,人们可以使用verbatim在 Yul 中实现它。...Optimism 目前使用一个自定义的 Solidity 编译器,因为他们模拟了智能合约的执行,其中对状态的改变(存储、外部调用等)都不会直接执行,而是由对管理人合约的调用来代替,该合约存储了这些改变以备验证...他们所做的是,检查合约是否使用了任何一个改变状态的操作码,除了调用管理人合约的 call操作码之外。...为了正确检测这个异常,导致这个call操作码的操作序列必须有一个特定的形式,通常,Solidity 优化器会进行一些重新排列,并破坏这个形式。
在 Solidity 发布之前,使用了其他语言,如 Serpent(已弃用)和 Mutan(已弃用)。 像 Solidity 这样的智能合约语言不能由 EVM 直接执行。...相反,它们需要被编译为低级别的指令(称为操作码)。 操作码 在底层,EVM 使用一组指令(称为操作码)来执行特定任务。 在撰写本文时,有 140 个唯一操作码。...每个操作码都分配有一个字节(例如;STOP 是 0x00)。 我们来看看下面的字节码:0x6001600101 在执行过程中,字节码被分成它的字节(1 个字节等于 2 个十六进制字符)。...,附加了一个由 Solidity 创建的元数据文件的 Swarm 散列。...在合约上调用函数时,函数签名是通过对函数名称(包括其输入)进行哈希处理(使用 keccak256)并截断除前 4 个字节之外的所有内容来确定的。
[1] 基础:solidity->bytecode(字节码)->opcode(操作码) 在我们开始前,这篇文章假定读者具备 solidity 的基础知识,以及了解它是如何部署在以太坊网络的。...本文将简要地讨论这部分知识,如果你想对这些知识进行系统复习,请看这篇文章[2]众所周知,solidity 代码在部署到以太坊网络之前需要被编译成字节码。...这个字节码对应的是 evm 所解析的一系列操作码指令。本系列文章主要分析编译后的字节码特定部分,并阐明它们的工作原理。在阅读完每篇文章后,你应该对每个组件的功能有一个更清晰的了解。...在文章的最后,你应该对这些操作码的作用有一个全面的了解。...JUMPI [0x6057361d] 到这里,在这个操作码执行后,你将被带到 store(uint256)的位置,然后函数的执行将继续正常执行。
对于普通编程语言而言,计算机做运算和改变程序的状态顶多只是费点电或者费点时间,但对于 EVM 兼容类的编程语言(例如 Solidity 和 Vyper),执行这些操作都是费钱 的!...如果想要识别这些模式并理解他们导致效率变高/低的原因,你必须首先对以太坊虚拟机(即 EVM)有一个基本的了解。 什么是 EVM?...如果你已经熟悉 EVM,请随时跳到下个部分: 什么是 EVM 操作码? 任何一个区块链都是一个基于交易的 状态机[7]。 区块链递增地执行交易,交易完成后就变成新状态。...Solidity 字节码示例 什么是 EVM 操作码? 所有以太坊字节码都可以分解为一系列操作数和操作码。操作码是一些预定义的操作指令,EVM 识别后能够执行这个操作。...下面是一些考虑了 EVM 操作码开销的反直觉设计模式的具体示例: 用乘法而不是指数: MUL vs EXP MUL 操作码花费 5 gas 用于执行乘法。
第 13 章 - 以太坊虚拟机[3] Openzepplin - 解构 Solidity 合约 一组博文,帮助你了解 solidity 代码是如何被 EVM 解释和执行的。...EVM 图解[18] EVM 代码 -- 操作码 的 EVM Playground 一个互动的网站和 EVM Playground。对 EVM 开发者来说是最有价值的工具之一。...它包含一个所有操作码的列表,以及描述和一个你可以观察它们如何工作的 Playground。...https://github.com/daltyboy11/more-evm-puzzles 区块链程序 -- 智能合约存储 一篇博文,对合约存储的数据结构做了很好的概述 了解以太坊智能合约存储[19]...Jeancvllr - EVM Assembly 一篇关于 EVM 汇编、操作码和在 solidity 中使用汇编的博文。
0xa9059cbb 执行后,在该To地址上发出了transfer的事件 分类有误则交易行为会误判 以交易行为为基石,则To地址能否被准确分类则对其CallData的判断会有截然不然的结论。...但是这个方法等于是单独对某个地址做获取,想要进一步提升精度和效率呢? 如果是部署合约的交易,如何在其刚执行完甚至他还在内存池中便获取部署的代码?...我做了个demo实现的时候,发现还好现在rpc的版本比较高,因为整个过程最难的便是执行3的时候,如何递归找到指定type的call,最底层的方式是通过opcode还原上下文,我吃了一惊!...solidity(高级语言)->bytecode(字节码)->opcode(操作码) 我们就可以清晰的发现一个特征,函数签名都会被PUSH4 这个操作码所执行,所以进一步的方法则是从全文中提取PUSH4...,我们上文方案里中基于REVER+JUMPDEST来做代码块的区分,结合其中必然的CallDate加载和位移来做唯一性判断,那是否存在,我可以用solidity合约也实现出类似的操作码序列呢?
如果我们只想提取实际数据,则需要跳过前32字节,从msg.data的0x20(32个字节)位置开始。这里,我们将利用两个操作码来执行该操作。...•0用于表示目标合约的返回值。这是未使用的,因为此时我们尚不知道返回数据的大小,因此无法将其分配给变量。之后我们可以使用returndata操作码访问此信息•0表示目标合约返回值的大小。...这是未使用的,因为在调用目标合约之前,我们是无法知道返回值的大小。...之后我们可以通过returndatasize操作码来获得该值 下一行,使用returndatasize操作码获取返回值的大小 let size := returndatasize 然后,我们使用returndatacopy...操作码将返回的数据拷贝到ptr变量中。
Remix这套课程,下面我再对每一节的视频,罗列出一些重点内容。...to brev breakpoint:跳转到上一个断点 Jump out:跳出 Stop debuging:停止调试 面板中会展示出很多信息,最核心的就是操作码面板,会显示当前执行到第几步和对应的操作码...另外,还有以下子面板: Function Stack:函数栈 Solidity State:显示合约的状态变量 Solidity Locals:局部变量,包括函数参数 Step details:当前操作码的详细信息...Storage:持久存储面板 Return Value:返回值 Global Variables:全局变量 我在实际测试时,其实这些面板通常展示的信息并不全,比如,Solidity State 面板并没有显示出状态变量...,Solidity State 也没有显示出全部局部变量,Return Value 也并没有显示出返回值。
在以太坊中对智能合约进行编程与常规开发人员所用的编程有很大不同,并且缺乏基本处理错误工具一直是一个问题,经常导致智能合约逻辑“破裂”。...• 我们想在同一个交易中重试调用、存储错误状态、对失败的调用做出处理等等。...参考文档: Solidity中文 文档-地址类型的成员[4] 请注意,在对 onlyEven(uint256) 的低级call调用返回了false的情况下,它会(必需)还原在低级调用执行中所做的状态更改...,但是在调用之前和/或之后的更改不会被还原应用。...•如果执行了 try 成功代码块,则必须声明与函数调用实际返回值相同类型的变量。•如果执行了低级的catch块,则返回值是类型为bytes的变量。任何特定条件的catch子句都有其自己的返回值类型。
现在Solidity对函数内局部变量采用C99类型的作用域解析规则,也就是变量只能在被声明后使用并且只在同一个作用域或者其下嵌套的(更深层次)作用域可见。...的参数 汇编中不允许使用jump,label以及非函数风格的指令 没实现的函数不允许使用modifier 函数类型中不允许包含返回值的名字,比如 ?...3.3 continue在do-while中的行为 当遇到循环体中的continue时,0.5.0中下一步会检查while中的条件,而之前则跳回执行循环体。...pure/view操作码(opcode)改为STATICCALL 声明为view的函数不修改状态。...访问block、tx、msg的成员(不包括msg.sig msg.data) 调用任何未标记为pure的函数 使用了包含某些操作码的内联汇编代码 在 0.5.0 之前,pure/view函数中可以使用非法的类型转换绕过对
领取专属 10元无门槛券
手把手带您无忧上云