NEO C# 合约编译器原理解析

Posted NEL新经济实验室

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NEO C# 合约编译器原理解析相关的知识,希望对你有一定的参考价值。

关注获取专业的区块链开发学习计划

NEO C# 合约编译器原理解析

NEO合约编译过程牵涉到几个项目

  1. neo-compiler下的neon项目负责code码转换

  2. neo-devpack-dotnetx下的Neo.SmartContract.Framework负责公共接口定义

  3. neo项目实现了framework中的接口

原理

c#的版本很多,从framework2.0到core2.3版本,语法差异很大,但是底层对应MSIL字节码没有变化,Neo的原理是先使用对应的编译器生成MSIL字节码,再把MSIL字节码转换成NEO vm的code码序列。这样做的好处在与利用了C#现有的语法成果,不必自己在设计一门语言,减少了合约编写的门槛。

大道不过三两行,说穿不值一文钱。下面我会通过一个完整的例子来说明这个流程,希望能藉此帮助更多人了解其中的原理细节,写出效率更好,费用更低的合约。

代码是在github上面找的,NEO-NEP5.1是NEP5的一个token,包含常用的元素,字段,事件与函数。具有常见的数据存储,合约调用及日志信息功能。

代码生成

c# -> MSIL

源码大致结构:实现细节摘除了,需要的请点击上面的链接

NEO C# 合约编译器原理解析

编译

NEO C# 合约编译器原理解析

编译完成后使用工具查看dll的类布局,其中字段还原没有问题,多了个类构造和构造函数,还有event对应出来的两个add/remove方法,后来在转换过程中都需要清除掉的.事实上在neo中event的更多的只是起到了标识的作用。具体的MSIL CODE太多就不贴上来了,下面提到哪里就贴到哪里.如果需要完整的文件,这里推荐一个常用工具ildasm,用来查看dll的语言信息十分方便。

NEO C# 合约编译器原理解析

MSIL -> 合约字节码

MSIL转换合约字节码工具是在neo-compiler/neon中定义的,转换命令为

NEO C# 合约编译器原理解析

这里可能会报错

NEO C# 合约编译器原理解析

这个错误估计是底下的库无法正确处理Action导致,这里手动定义下事件,改变下原来Transfer的定义,熟悉C#语法的人应该知道这两种写法几乎是等同的。

NEO C# 合约编译器原理解析

修改完成后重新执行命令‘dotnet . eon.dll NEP.dll’。看到如下字样即是成功的转换了类库,此时在运行目录下可以看到一个NEP.avm和一个NEP.abi的文件,前者包含了运行所需的字节码,后者仅仅描述了方法和事件信息。

NEO C# 合约编译器原理解析

到这neo字节码生成完毕,然后就按官方的方法把这个vm文件发布出去。

代码调用

合约代码入口就是文件的main函数,通常是根据传入的函数名称判断调用到对应的工作函数。下面会通过两个具体函数的执行过程,通过对比三种代码来说明这个编译执行的过程。

部署合约函数流程

入口跳转

c#

NEO C# 合约编译器原理解析

MSIL

NEO C# 合约编译器原理解析

VM OPCODE

NEO C# 合约编译器原理解析

其中主要看两条指令,一个是IL_0081/013A,一个是IL_008c/014B,前者就是判断参数是不是depoly,后者是判断成功后进行函数跳转,调用需要执行的函数。

调用部署函数

c#

NEO C# 合约编译器原理解析

MSIL

NEO C# 合约编译器原理解析

VM OPCODE

NEO C# 合约编译器原理解析

几个重要的函数调用位置对比:

检查合约所有人

NEO C# 合约编译器原理解析

错误提示:You are not the Owner of this Smart Contract

NEO C# 合约编译器原理解析

获取当前合约币供应量totalSupply

NEO C# 合约编译器原理解析

错误提示:防止重复调用

NEO C# 合约编译器原理解析

设置初始供应量

NEO C# 合约编译器原理解析

打印日志

NEO C# 合约编译器原理解析

转账合约函数调转逻辑

入口跳转

c#

NEO C# 合约编译器原理解析

MSIL

NEO C# 合约编译器原理解析

VM OPCODE

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

指令IL_0233/03E3用于确认要调用的函数是否是transfer,IL_0274/0477 用于打印错误日志信息,指令IL_02a9/04DB调用转账函数。

调用转账函数

c#

NEO C# 合约编译器原理解析

MSIL

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

VM OPCODE

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

提示资产错误

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

NEO C# 合约编译器原理解析

打印输出日志

NEO C# 合约编译器原理解析

函数分类

当前使用的版本最常见的就是SYSCALL和CALL_I。

SYSCALL

用于调用外部接口函数,VM定义了一系列的外部接口,接口定义可以在Neo.SmartContract.Framework项目中查看,这些函数实现在Neo项目的SmartContract文件夹下面,函数使用SyscallAttribute标记,合约调用时候会按名索引到对应的执行函数。这里以Storage为例子说明这个问题。

定义

NEO C# 合约编译器原理解析

实现

StateMachine继承自neo-vmsrc eo-vmInteropService.cs文件中的InteropService,每次调用Register时,会在其中注册入实现函数,调用时通过名字查找到这个函数,在传入参数执行。

Storage_Put 具体实现

NEO C# 合约编译器原理解析

注册函数实现

NEO C# 合约编译器原理解析

注册函数

NEO C# 合约编译器原理解析

转换

转换主要是通过判断函数是否有SyscallAttribute来确定,如果是的会把函数名称及参数信息添加上去。

判断函数

NEO C# 合约编译器原理解析

转换Syscall

NEO C# 合约编译器原理解析

使用

NEO C# 合约编译器原理解析

CALL_I

用于合约内部函数调用

定义

在合约中自己定义的方法都符合这个类型,如例子中的转账及部署等。

NEO C# 合约编译器原理解析

转换

判断,如果在当前使用的合约机器类库中存在该实现,则确定为这种类型的调用

NEO C# 合约编译器原理解析

转换

NEO C# 合约编译器原理解析

使用

这种调用直接跳转到对应的指令位置执行。

NEO C# 合约编译器原理解析

日志信息

日志提供了一种方式用于我们观察判断合约执行的状态,日志有两种使用方式,一种通过event定义日志,另一种直接调用Neo.Runtime.Notify函数,实质上呢,前者经过一系列的转换步骤后也是转换到Neo.Runtime.Notify逻辑当中,Neo.Runtime.Notify是一种SysCall,最终在执行器中注册如具体的Notify通知实现,因而这里自讨论下event的方式。

定义

NEO C# 合约编译器原理解析

转换

因为C#的事件直接执行,实际到MSIL层转换成Invoke调用,其中更多细节可以去研究下C#Delegate,event的具体实现机制,此处不多赘言。

事件解析:解析出来的东西并没啥用,只要在到处json时能看到个事件项目,函数实际上还是去搜索

NEO C# 合约编译器原理解析

Invoke查找,之前有提过event和Nottify本质上是相同的,相同之处就体现在IsNotifyCall函数中,该函数会判断函数名称是否是Invoke,类型就粗暴的判断了Action。满足就是个NotifyCall了,返回的函数名就不用在意了,最后转换的时候给统统变成一个名字:Neo.Runtime.Notify。

NEO C# 合约编译器原理解析

转换

NEO C# 合约编译器原理解析

Neo.Runtime.Notify 定义

NEO C# 合约编译器原理解析

使用

c#中调用

NEO C# 合约编译器原理解析

Vm执行Neo.Runtime.Notify Syscall.

NEO C# 合约编译器原理解析

数据存储

Neo的数据存储主要通过Storage接口提供,外部实现的数据库存储,具体参考上面给的代码例子,Neo合约也不支持普通成员变量,但是静态成员是支持的,原因在于,静态成员编译即确定,在转换的过程中会在每个使用到静态变量的地方嵌入实际的值。


如果你对区块链有兴趣

想从一名开发者转型为区块链开发者

欢迎加入NEL开发者社区

 

在这里,你可以得到专业的区块链开发学习计划

NEL将不定期的在社区分享开发技术文章视频干货

也会不定期邀请区块链技术大咖进行线下面对面分享

我们会以线下讲座、线上直播、社区问答、文字介绍等形式推广NEO区块链平台

同时我们会发布一些简单又具有意义的开发任务帮助初学者练习提高


NEL是NEO生态的中国开发者社区。作为NEO区块链技术、智能合约技术推广的核心力量,致力于培养社区开发人才,推动项目落地,发展NEO社区生态。建立完整的社区人才发展体系,以适应不同层次的开发者参与区块链项目的需求。

NEL的使命是帮助优秀的区块链开发者抓住区块链技术所提供的难得机遇,实现开发者改变世界的理想,帮助开发者成功。


以上是关于NEO C# 合约编译器原理解析的主要内容,如果未能解决你的问题,请参考以下文章

Java即时编译器原理解析及实践

NEO从入门到开窗 - NEO编译器

内核级python:编译器的词法和语法解析基本原理

基本功 | Java即时编译器原理解析及实践

第 60 期Java 即时编译器原理解析及实践

Android-ARouter原理解析