zoukankan      html  css  js  c++  java
  • NEO从入门到开窗(3)

    一、啰嗦两句

    第一节的时候咱说了C#编译完了之后,就该NEO的编译器搞事情了。我们完全可以按这个节奏搞,手动用NEO的编译器neon编译dll文件生成指令码文件.avm。但是NEO团队给我们写智能合约提供了个插件,咱们就先看看这玩意怎么玩,然后简单的介绍一下NEO的编译器源码。

    二、NeoContractPlugin

    咱在VS里【工具】-》【扩展和更新】里搜下NeoContractPlugin,安装这个模板。

    完事新建项目时候就能新建一个NeoContract的项目了

    创建完之后,就是这样滴。

    好,按NEO的模板创建出来的东东,多了build.tasks和Neo.ConvertTask.dll这俩文件,除此之外,在项目文件里还导入了一个project和AfterBuild之后的任务。这里做的事情,其实就是告诉项目编译完了之后跑一个ConvertTask的任务,看到项目里的Neo.ConvertTask.dll了么,后面我们介绍它。 

     

    ConvertTask这个任务是干嘛的,我们来看一眼源码,源码在项目neo-devpack-dotnet中

    using Microsoft.Build.Framework;
    using Microsoft.Build.Utilities;
    using System.Diagnostics;
    
    namespace Neo
    {
        /// <summary>
        /// this class generate config / xml file by template
        /// </summary>
        public class ConvertTask : Task
        {
            [Required]
            public ITaskItem DataSource { get; set; }
    
            /// <summary>
            /// execute replace logic
            /// </summary>
            /// <returns>ture successful, false failure</returns>
            public override bool Execute()
            {
                var srcdll = this.DataSource.ToString();
                string dllname = System.IO.Path.GetFileName(srcdll);
                ProcessStartInfo pinfo = new ProcessStartInfo();
                pinfo.FileName = "cmd.exe";
                pinfo.WorkingDirectory = System.IO.Path.GetDirectoryName(srcdll);
                pinfo.UseShellExecute = false;
                pinfo.RedirectStandardInput = true;
                pinfo.RedirectStandardOutput = true;
                pinfo.CreateNoWindow = true;
                pinfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
    
                Process p = Process.Start(pinfo);
                p.StandardInput.AutoFlush = true;
                p.StandardInput.WriteLine("neon " + dllname);
                p.StandardInput.WriteLine("exit");
    
                //前四行后一行不要
                string lastline = null;
                int count = 0;
                bool bSucc = false;
                while (p.StandardOutput.EndOfStream == false)
                {
                    var line = p.StandardOutput.ReadLine();
                    count++;
                    if (count <= 4) continue;
    
                    if (lastline != null && lastline.Length > 0)
                    {
                        if (lastline[0] == '<')
                        {
                            if (lastline.IndexOf("<WARN>") == 0)
                            {
                                this.Log.LogWarning(lastline.Substring(6));
                                lastline = line;
                                continue;
                            }
                            else if (lastline.IndexOf("<ERR>") == 0)
                            {
                                this.Log.LogError(lastline.Substring(5));
                                lastline = line;
                                continue;
                            }
                            else if (lastline.IndexOf("<WARN|") == 0)
                            {
                                var l = lastline.Substring(6);
                                var ine = lastline.IndexOf(">");
                                var text = lastline.Substring(ine + 1);
                                var file = lastline.Substring(6, ine - 6);
                                var lines = file.Split(new char[] { '(', ')' });
                                int _line = 0;
                                if (lines.Length > 1)
                                {
                                    int.TryParse(lines[1], out _line);
                                }
                                this.Log.LogWarning("", "", "", lines[0], _line, 0, 0, 0, text);
                                lastline = line;
                                continue;
                            }
                            else if (lastline.IndexOf("<ERR|") == 0)
                            {
                                var l = lastline.Substring(5);
                                var ine = lastline.IndexOf(">");
                                var text = lastline.Substring(ine + 1);
                                var file = lastline.Substring(5, ine - 5);
                                var lines = file.Split(new char[] { '(', ')' });
                                int _line = 0;
                                if (lines.Length > 1)
                                {
                                    int.TryParse(lines[1], out _line);
                                }
                                this.Log.LogWarning("", "", "", lines[0], _line, 0, 0, 0, text);
                                lastline = line;
                                continue;
                            }
                        }
                        if (lastline.IndexOf("SUCC") == 0)
                        {
                            bSucc = true;
                        }
                        this.Log.LogMessageFromText(lastline, MessageImportance.High);
    
                    }
    
                    lastline = line;
                    //lines.Add(line);
                }
    
                //this.Log.LogMessageFromText(lastline, MessageImportance.High);
    
                p.WaitForExit();
                return bSucc;
            }
        }
    
    }
    ConvertTask

    好,先不管细节,就是起了一个cmd进程跑neon,其实就是帮我们调了一下NEO的编译器,妥了,那咱们就看看编译器搞了些撒事情吧。

    三、NEO编译器

    这一部分最好还是看看源码,我就简单介绍一下。这里有三个类比较关键:

    1. ModuleDefination: 这个类是用的库Mono.cecil,这个库可以查看或者修改IL文件,这里是官方地址:http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/

    2. ILModule: 这个是编译器里定义的一个类,类的主要方法就是LoadModule,一看就明白了,其实现正是使用ModuleDefination加载并读取IL文件,将其转化为ILModule。这里其实还是用一种数据类型记录的智能合约代码的元数据信息,方法、字段、属性等的描述信息,可以理解成我们用反射操作类型。

    3. NeoModule: 这个是另外一个数据结构,通过一个ModuleConverter的类从ILModule逐条指令转化进NeoModule,这个结构里保持了一个有序字典,value就是转化后的指令码,也就是我们说的OpCode。之后就是把这个NeoModule Build成字节数组写入.avm文件。

    理解这三个类的含义就明白编译器的流程了。这里的难点是指令码,非常多,所以需要详细了解的自己看下源码吧。

    四、小结

    好了,今天就简单讲了一下NEO的智能合约模板背后都搞了啥,以及NEO编译器大概怎么编译的。通过前面几讲,大伙儿应该从工程的角度对NEO的智能合约这部分有些了解了。

    后续,准备从NEO的命令行全节点Neo-cli入手讲讲NEO的内部机制。

  • 相关阅读:
    人生苦短,我用python!
    Pycharm快捷键
    查看java进程
    带你掌握Arthas
    高并发场景下System.currentTimeMillis()的性能问题的优化
    SpringBoot整合Dubbo&ZooKeeper
    CentOS7下yum安装Mysql5.7
    SpringCache整合Redis实现自定义缓存时间
    Java开发神器lombok
    CentOS7安装Nginx
  • 原文地址:https://www.cnblogs.com/DexterDi/p/8627621.html
Copyright © 2011-2022 走看看