Neo 虛擬機

上一篇《Neo 編譯器》中說明了Neo編譯器是怎麼把CIL轉成neo虛擬機的opcode,那麼vm虛擬機又是怎麼處理這些代碼的,這篇文章咱們看一下虛擬機的代碼。git

框架

虛擬機所處的位置github

 

在框架圖中,咱們能夠看出Virtual Machine有如下做用框架

  1. 讀取Opcode(smart contract),在Execution Engine中執行
  2. Execution Engine能夠進行邏輯運算
  3. Interop Service能夠調用External Data
  4. 系統調用(OP_SYSCALL)能夠訪問區塊鏈帳本的信息

下面咱們先看一下虛擬機如何讀取Opcode。函數

VM對象關係

下面展現的圖不是UML, UML太麻煩,仍是腦圖比較符合思惟邏輯的發展。區塊鏈

 

關鍵的幾個對象測試

  1. Execution Engine:執行引擎
  2. Execution Context:執行上下文
  3. Stack Item:堆棧的一條數據
  4. Crypto:C#的加密庫

執行引擎

執行引擎ui

  1. IScriptTable裏面存貯了AppCall命令能夠調用的其餘contract的代碼,這一塊須要研究一下區塊鏈的實現,這個之後再仔細研究。
  2. InteropService專門用來響應SYSCALL,具體有哪些是系統調用,用來幹什麼的,後面經過例子再來講明。
  3. InvocationStack是調用棧,傳入參數,調用其餘合約都會有一個新的調用棧
  4. EvaluationStack是計算棧,用來執行操做
  5. AltStack是備用棧,計算棧算出的中間結果能夠保存在備用棧

執行上下文

執行上下文加密

 

每一個變量都蠻好理解的,重點是下面看看怎麼用的。lua

vm執行流程

vm代碼執行流程spa

  1. 構造,此時能夠傳入script container,script table,後面咱們看看在區塊鏈上這些都是從哪裏來的,這裏只專一於vm的執行流程,暫且不深究了。
    2.加載.avm,avm是編譯器編譯出來的一串數字,經過engine.LoadScript能夠加載。
  2. 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();

  1. 代碼執行完了之後,插入OpCode.RET
  2. 若是不是RET,則read一個字節的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

具體的執行過程

 

總結

文章只是過了一下一個簡單的代碼,後面咱們須要研究一下系統調用和訪問外部存貯,智能合約之間互相調用的狀況。

 

進技術羣交流:795681763

相關文章
相關標籤/搜索