以太坊虚拟机(EVM)是一个256位、基于堆栈、全球可访问的图灵机。由于架构与其他虚拟机和物理机的明显不同,EVM需要领域特定语言DSL。
在本文中,我们将研究EVMDSL设计的最新技术,介绍六种语言Solidity、Vyper、Fe、Huff、Yul和ETK。
语言版本
Solidity:0.8.19
Vyper:0.3.7
Fe:0.21.0
Huff:0.3.1
ETK:0.2.1
Yul:0.8.19
阅读本文,需要你对EVM、堆栈和编程有基本的了解。
以太坊虚拟机概述
EVM是一个基于256位堆栈的图灵机。然而,在深入研究它的编译器之前,应该介绍一些功能特性。
由于EVM是「图灵完备」的,它会受到「停机问题」的困扰。简而言之,在程序执行之前,没有办法确定它未来是否会终止。EVM解决这个问题的方法是通过「Gas」计量计算单位,一般来说,这与执行指令所需的物理资源成比例。每个交易的Gas量是有限制的,交易的发起者必须支付与交易消耗的Gas成比例的ETH。这个策略的影响之一是,如果有两个功能上相同的智能合约,消耗更少Gas的合约将被更多采用。这导致协议竞争极端的Gas效率,工程师努力最小化特定任务的Gas消耗。
此外,当调用一个合约时,它会创建一个执行上下文。在这个上下文中,合约有一个堆栈用于操作和处理,一个线性内存实例用于读写,一个本地持久性存储用于合约读写,并且附加到调用的数据「calldata」可以被读取但不能被写入。
西班牙央行副行长:推出数字欧元之前需要衡量其对银行系统的影响:金色财经报道,西班牙央行副行长德尔加多:欧洲央行7月会议的措辞略有修改,以保留在9月暂停加息的可能性。在决定推出数字欧元之前,我们需要衡量其对银行系统的影响。[2023/8/25 10:02:32]
关于内存的一个重要说明是,虽然它的大小没有确定的「上限」,但仍然是有限的。扩展内存的Gas成本是动态:一旦达到阈值,扩展内存的成本将呈二次方增长,也就是说Gas成本与额外内存分配的平方成正比。
合约也可以使用一些不同的指令来调用其他合约。「call」指令将数据和可选的ETH发送到目标合约,然后创建自己的执行上下文,直到目标合约的执行停止。「staticcall」指令与「call」相同,但增加了一个检查,即在静态调用完成之前,断言全局状态的任何部分都未被更新。最后,「delegatecall」指令的行为类似于「call」,只是它会保留先前上下文的一些环境信息。这通常用于外部库和代理合约。
为什么语言设计很重要
在与非典型架构交互时,特定领域语言是必要的。虽然存在诸如LLVM之类的编译器工具链,但是依赖它们来处理智能合约,在程序正确性和计算效率至关重要的情况下,不太理想。
程序正确性非常重要,因为智能合约默认是不可变的,并且鉴于区块链虚拟机的属性,智能合约是金融应用程序的热门选择。虽然存在针对EVM的升级性解决方案,但它充其量只是一个补丁,最坏的情况是任意代码执行漏洞。
计算效率也非常关键,因为最小化计算具有经济优势,但不能以安全为代价。
简而言之,EVMDSL必须平衡程序正确性和Gas效率,在不牺牲太多灵活性的情况下通过做出不同的取舍来实现其中之一。
Gate.io于5月6日22:05-22:20(UTC+8)进行现货交易引擎升级,目前数据显示已恢复:据官方消息,由于Gate.io于2023年5月6日22:05-22:20(UTC+8)进行现货交易引擎升级,升级过程中出现显示数据推送阻塞,影响了用户前端的资产数据显示,但实际用户持仓和交易均未受影响。目前数据显示已恢复。该升级于今日早些时候已进行公告公示。[2023/5/7 14:47:34]
语言概览
对于每种语言,我们将描述它们的显着特性和设计选择,并包括一个简单的计数功能智能合约。言语流行度是根据DefiLlama上的总锁定价值(TVL)数据确定的。
Solidity
Solidity是一种高级语言,其语法类似于C、Java和Javascript。它是按TVL计算最受欢迎的语言,其TVL是第二名的十倍。为了代码重用,它使用面向对象模式,智能合约被视为类对象,利用了多重继承。编译器采用C++编写,计划在将来迁移到Rust。
可变的合约字段存储在持久性存储中,除非它们的值在编译时或部署时已知。合约内声明的方法可以声明为pure、view、payable,或默认情况下是non-payable但状态可修改。pure方法不会从执行环境中读取数据,也不能读取或写入持久性存储;也就是说,给定相同的输入,pure方法将始终返回相同的输出,它们不会产生副作用。view方法可以从持久性存储或执行环境中读取数据,但它们不能写入持久性存储,也不能创建副作用,例如附加事务日志。payable方法可以读写持久性存储,从执行环境中读取数据,产生副作用,并且可以接收附加在调用中的ETH。non-payable方法与payable方法相同,但具有运行时检查,以断言当前执行上下文中没有附加ETH。
Yuga Labs已为“Otherside”主题饮料申请商标:3月5日消息,根据美国专利局披露信息显示,Yuga Labs已为以旗下元宇宙项目“Otherside”为主题的饮料申请了商标。
据悉,Yuga Labs一直在为The Otherside的发布做准备,而在一年前的Otherside预告片中就展示过一款名为“Don’t Drink Me”的饮料,本次申请的商标中也有该字样,目前商标涵盖范围包括啤酒类、能量饮品、不含酒精的饮料、软饮料、水果汁、苏打水、苹果酒等。(uspto)[2023/3/5 12:43:31]
注意:将ETH附加到交易中与支付Gas费用是分开的,附加的ETH由合约接收,可以通过恢复上下文选择接受或拒绝它。
在合约的范围内声明时,方法可以指定以下四种可见性修饰符:private、internal、public或external。private方法可以通过当前合约内的「jump」指令在内部访问。任何继承的合约都不能直接访问private方法。internal方法也可以通过「jump」指令在内部访问,但继承的合约可以直接使用内部方法。public方法可以通过「call」指令由外部合约访问,创建一个新的执行上下文,并在直接调用方法时通过跳转进行内部访问。public方法也可以通过在方法调用前加上「this.」来在新的执行上下文中从同一合约中访问。external方法只能通过「call」指令访问,无论是来自不同的合约还是在同一合约内,都需要在方法调用前加上「this.」。
注意:「jump」指令操作程序计数器,「call」指令为目标合约的执行期间创建一个新的执行上下文。在可能的情况下,使用「jump」而不是「call」更加节约Gas。
Solidity还提供了三种定义库的方式。第一种是外部库,它是一个无状态的合约,单独部署到链上,在调用合约时动态链接,并通过「delegatecall」指令访问。这是最不常见的方法,因为外部库的工具支持不足,「delegatecall」很昂贵,它必须从持久存储中加载额外的代码,并且需要多个事务进行部署。内部库的定义方式与外部库相同,只是每个方法必须定义为内部方法。在编译时,内部库被嵌入到最终合约中,并且在死代码分析阶段,库中未使用的方法将被删除。第三种方式与内部库类似,但不是在库内定义数据结构和功能,而是在文件级别定义,并且可以直接导入和在最终合约中使用。第三种方法提供了更好的人机交互性,可以使用自定义数据结构,将函数应用于全局作用域中,并一定限程度上将别名运算符应用于某些函数。
数字银行FV Bank宣布与Circle集成:金色财经报道,美国数字银行FV Bank今天宣布为FV Bank账户持有人推出一项新服务:能够即时并在存款时自动将Circle的美元硬币(USDC)转换为美元。(finextra)[2022/9/21 7:11:29]
编译器提供两个优化通道。第一个是指令级优化器,对最终的字节码执行优化操作。第二个是近期增加使用Yul语言作为编译过程中的中间表示,然后对生成的Yul代码进行优化操作。
为了与合约中的公共和外部方法交互,Solidity规定了一种应用程序二进制接口标准来与其合约交互。目前,SolidityABI被视为EVMDSL的事实标准。指定外部接口的以太坊ERC标准都按照Solidity的ABI规范和风格指南来执行。其他语言也遵循Solidity的ABI规范,很少出现偏差。
Solidity还提供了内联Yul块,允许对EVM指令集进行低级别访问。Yul块包含Yul功能的子集,详细信息请参见Yul部分。这通常用于进行Gas优化,利用高级语法不支持的功能,并自定义存储、内存和calldata。
由于Solidity的流行,开发人员工具非常成熟且设计精良,Foundry是在这方面突出的代表。
以下是用Solidity编写的一个简单合约:
Vyper
Vyper是一种语法类似于Python的高级语言。它几乎是Python的一个子集,只有一些小的不同。它是第二受欢迎的EVMDSL。Vyper针对安全性、可读性、审计能力和Gas效率进行了优化。它不采用面向对象模式、内联汇编,并且不支持代码重用。它的编译器是用Python编写的。
报告:11.4%的阿联酋居民投资了加密货币:金色财经报道,根据阿联酋电信监管机构TDRA的一项研究,该国约11.4%的居民拥有或投资了加密货币;从全球范围来看,阿联酋现在跻身加密投资居民最多的十大国家之列。
此前消息,阿联酋通过虚拟资产监管局 (VARA) 等监管机构向Binance、FTX和OKX等加密货交易平台颁发了许可证。此外,通过阿布扎比全球市场 (ADGM),该国一直致力于创建符合全球标准的监管框架。(news.bitcoin)[2022/9/4 13:08:08]
存储在持久性存储器中的变量是在文件级别声明的。如果它们的值在编译时已知,可以将它们声明为「constant」;如果它们的值在部署时已知,则可以将它们声明为「immutable」;如果它们被标记为public,则最终合约将为该变量公开一个只读函数。常量和不变量的值通过它们的名称在内部访问,但是持久性存储器中的可变量可以通过在名称前面添加「self.」来访问。这对于防止存储变量、函数参数和局部变量之间的命名空间冲突非常有用。
和Solidity类似,Vyper也使用函数属性来表示函数的可见性和可变性。被标记为「@external」的函数可以通过「call」指令从外部合约访问。被标记为「@internal」的函数只能在同一合约中访问,并且必须以「self.」为前缀。被标记为「@pure」的函数不能从执行环境或持久存储中读取数据,也不能写入持久存储或创建任何副作用。被标记为「@view」的函数可以从执行环境或持久存储中读取数据,但不能写入持久存储或创建副作用。被标记为「@payable」的函数可以读取或写入持久存储,创建副作用,接受收ETH。没有声明这个可变性属性的函数默认为non-payable,也就是说,它们和payable函数一样,但不能接收ETH。
Vyper编译器还选择将局部变量存储在内存中而不是堆栈上。这使得合约更加简单和高效,并解决了其他高级语言中常见的「堆栈过深」的问题。但是,这也带来了一些折衷。
另外,由于内存布局必须在编译时知道,因此动态类型的最大容量也必须在编译时知道,这是一个限制。此外,分配大量内存会导致非线性的Gas消耗,正如EVM概述部分中提到的。但是,对于许多用例来说,这个Gas成本可以忽略不计。
虽然Vyper不支持内联汇编,但它提供了更多内置函数,以确保几乎每个Solidity和Yul中的功能在Vyper中也可以实现。通过内置函数可以访问低级位运算、外部调用和代理合约操作,通过编译时提供覆盖文件可以实现自定义存储布局。
Vyper没有丰富的的开发工具套件,但它有更紧密集成的工具,并且也可以插入到Solidity开发工具中。值得关注的Vyper工具包括Titanaboa解释器,它具有许多与EVM和Vyper相关的内置工具,可用于实验和开发,以及Dasy,一种基于Vyper的Lisp,具有编译时代码执行功能。
下面是用Vyper编写的一个简单合约:
Fe
Fe是一种类似Rust的高级语言,目前正在积极开发中,大部分功能尚未推出。它的编译器主要用Rust编写,但使用Yul作为其中间表示形式,依赖于用C++编写的Yul优化器。随着Rust原生后端Sonatina的加入,这一点有望改变。Fe使用模块进行代码共享,因此不使用面向对象的模式,而是通过基于模块的系统重用代码,在模块内声明变量、类型和函数,可以以类似于Rust的方式进行导入。
持久存储变量在合约级别声明,如果没有手动定义的getter函数则不可公开访问。常量可以在文件或模块级别声明,并且可以在合约内部访问。当前不支持不可变的部署时变量。
方法可以在模块级别或合约内声明,默认是pure和private。要使合约方法公开,必须在定义前加上「pub」关键字,这使得它可以在外部访问。要从持久化存储变量中读取,方法的第一个参数必须是「self」,在变量名前加上「self.」,使该方法具有只读访问本地存储变量的权限。要读取和写入持久化存储,第一个参数必须是「mutself」。「mut」关键字表示合约的存储在方法执行期间是可变的。访问环境变量是通过将「Context」参数传递给方法来完成的,通常命名为「ctx」。
函数和自定义类型可以在模块级别声明。默认情况下,模块项都是私有的,除非加上「pub」关键字才能访问。但是,不要和合约级别的「pub」关键字混淆。模块的公共成员只能在最终合约或其他模块内部访问。
Fe暂时不支持内联汇编,相反,指令由编译器内部函数或在编译时解析为指令的特殊函数包装。
Fe遵循Rust的语法和类型系统,支持类型别名、带有子类型的枚举、特征和泛型。目前这方面的支持还有限,但正在进行中。特征可以针对不同类型进行定义和实现,但不支持泛型,也不支持特征约束。枚举支持子类型,并可以在其上实现方法,但不能在外部函数中对其进行编码。尽管Fe的类型系统仍在发展中,但它在为开发人员编写更安全、编译时检查的代码方面显示出了很大的潜力。
下面是用Fe编写的一个简单的合约:
Huff
Huff是一种汇编语言,具有手动堆栈控制和对EVM指令集的最小化抽象。通过「Billions项目组definefn」指令定义,可以接受模板参数以提高灵活性,并指定函数开始和结束时的预期堆栈深度。由于这些函数是内部的,因此无法从外部访问,在内部访问需要使用「jump」指令。
其他控制流程,例如条件语句和循环语句可以使用跳转目标定义。跳转目标是由标识符后跟冒号定义的。可以通过将标识符压入堆栈并执行跳转指令来跳转到这些目标。这在编译时解析为字节码偏移量。
宏由「Billions项目组、Swift和Kotlin到Solidity、Sway和Cairo。学习在这些语言之间无缝切换为软件工程职业提供了无与伦比的灵活性。最后,重要的是要了解每一种语言背后都需要付出大量的工作。没有人是完美的,但无数有才华的人付出了大量努力,为像我们这样的开发者创造安全愉快的体验。
刷推特、看研报累不累?脱水大字报帮你筛选和梳理每日重要市场观点和研报。该内容由几位交易员和分析师志愿者利用业余时间完成,请大家关注点赞给予鼓励,欢迎留言互动,申请入群一起交流.
1900/1/1 0:00:00刷推特、看研报累不累?脱水大字报帮你筛选和梳理每日重要市场观点和研报。该内容由几位交易员和分析师志愿者利用业余时间完成,请大家关注点赞给予鼓励.
1900/1/1 0:00:00美国2020年总统大选,据多家美国媒体当地时间13日对所有州选举人票的统计结果,民主党总统候选人拜登以306张选举人票战胜了共和党总统候选人、现任总统特朗普.
1900/1/1 0:00:001Inch的空投错过了,有点可惜。从8月份就在提醒自己去操作,结果还是被惰性耽误了,白白错过了一个大羊毛。有多少人跟雪儿一样的,因为怕麻烦,因为习惯了一个软件就不想挪窝,然后就拍大腿。。
1900/1/1 0:00:00刷推特、看研报累不累?脱水大字报帮你筛选和梳理每日重要市场观点和研报。该内容由几位交易员和分析师志愿者利用业余时间完成,请大家关注点赞给予鼓励.
1900/1/1 0:00:00两周多以来,领先的加密货币比特币一直在31250美元至29640美元之间震荡横盘。尽管近期美国证券交易委员会表示比特币ETF现货申请不足,导致市场情绪波动,但比特币价格仍遵循这一区间并保持在一定.
1900/1/1 0:00:00