ネオ仮想マシン

3865 ワード

前の「Neoコンパイラ」では、NeoコンパイラがCILをneo仮想マシンのopcodeにどのように変換するかを説明していますが、vm仮想マシンはこれらのコードをどのように処理しているのか、この文章では仮想マシンのコードを見てみましょう.

フレーム


仮想マシンの場所
フレームワーク図では、Virtual Machineが次のような役割を果たしていることがわかります.
  • Opcode(smart contract)を読み出し、Execution Engineで
  • を実行する.
  • Execution Engine論理演算
  • Interop ServiceはExternal Data
  • を呼び出すことができる.
  • システム呼び出し(OP_SYSCALL)は、ブロックチェーン帳簿の情報
  • にアクセスすることができる.
    次に、仮想マシンがOpcodeを読み込む方法を見てみましょう.

    VMオブジェクト関係


    以下に示す図はUMLではなく、UMLが面倒なのか、それとも脳図が思考論理の発展に合っているのか.
    重要なオブジェクト
  • Execution Engine:実行エンジン
  • Execution Context:実行コンテキスト
  • Stack Item:スタックのデータ
  • Crypto:C#の暗号化ライブラリ
  • 実行エンジン

  • IScriptTableにはAppCallコマンドで呼び出せる他のcontractのコードが格納されています.このブロックはブロックチェーンの実現を検討する必要があります.これは後で詳しく検討します.
  • InteropServiceはSYSCALLに応答するために使用され、具体的にはシステム呼び出し、何に使用されるかは、後で例を挙げて説明します.
  • InvocationStackは呼び出しスタックであり、パラメータが入力され、他の契約を呼び出すと新しい呼び出しスタック
  • がある.
  • EvaluationStackは、動作
  • を実行するための計算スタックである.
  • AltStackはスタンバイスタックであり、計算スタックで算出された中間結果はスタンバイスタック
  • に保存することができる.

    実行コンテキスト


    実行コンテキスト
    各変数はよく理解されていますが、ポイントは以下でどのように使うかを見ることです.

    vm実行プロセス


    vmコード実行プロセス
  • 構造で、このときscript container,script tableに入ることができ、後でブロックチェーンでこれらがどこから来たのかを見てみましょう.ここではvmの実行プロセスだけに集中しています.
  • ロード.avm,avmはコンパイラがコンパイルした一連の数字で、engine.LoadScriptはロードできます.

  • executeが実行を開始します.コードを見てみましょう.
       public void Execute()
            {
                State &= ~VMState.BREAK;
                while (!State.HasFlag(VMState.HALT) && !State.HasFlag(VMState.FAULT) && !State.HasFlag(VMState.BREAK))
                    StepInto();
            }
     public void StepInto()
            {
                if (InvocationStack.Count == 0) State |= VMState.HALT;
                if (State.HasFlag(VMState.HALT) || State.HasFlag(VMState.FAULT)) return;
                OpCode opcode = CurrentContext.InstructionPointer >= CurrentContext.Script.Length ? OpCode.RET : (OpCode)CurrentContext.OpReader.ReadByte();
                try
                {
                    ExecuteOp(opcode, CurrentContext);
                }
                catch
                {
                    State |= VMState.FAULT;
                }
            }

    この行のコードを見てください.OpCode opcode=CurrentContext.InstructionPointer >= CurrentContext.Script.Length ? OpCode.RET : (OpCode)CurrentContext.OpReader.ReadByte();
  • コードの実行が完了する後、OpCodeを挿入する.RET
  • RETでない場合、read 1バイトのopcode
  • ExecuteOp関数はOpCodeを実行する具体的な意味であり,一例で説明する.

    具体的な例


    前回のコードです
    using Neo.SmartContract.Framework;
    using Neo.SmartContract.Framework.Services.Neo;
    
    public class Sum : SmartContract
    {
        public static int Main(int a, int b)
        {
            return a + b;
        }
    }
    

    仮想マシンのコードのテスト
    using System;
    using System.IO;
    using System.Linq;
    using Neo;
    using Neo.VM;
    using Neo.Cryptography;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var engine = new ExecutionEngine(null, Crypto.Default);
                engine.LoadScript(File.ReadAllBytes(@"C:\……\Test1.avm")); 
    
                using (ScriptBuilder sb = new ScriptBuilder())
                {
                    sb.EmitPush(4); //   b
                    sb.EmitPush(3); //   a
                    engine.LoadScript(sb.ToArray());
                }
    
                engine.Execute(); //  
    
                var result = engine.EvaluationStack.Peek().GetBigInteger(); //  
                Console.WriteLine($"  {result}");
                Console.ReadLine();
            }
        }
    }
    

    実行される特定のプロセス


    生成されたコードは長すぎて、少し辛抱強く見ることができて、もし画像がはっきりしないならば、コード倉庫に行ってpdfをダウンロードすることができます
    具体的な実行プロセス

    まとめ


    文章は簡単なコードを過ぎただけで、後でシステム呼び出しと外部ストレージへのアクセス、スマート契約の間で相互に呼び出される状況を検討する必要があります.
    作者:沈寅原文リンク:https://www.jianshu.com/p/b7a...