溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

NEO VM原理及其實現(xiàn)是怎樣的

發(fā)布時間:2021-12-03 19:02:34 來源:億速云 閱讀:130 作者:柒染 欄目:互聯(lián)網(wǎng)科技

NEO VM原理及其實現(xiàn)是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

NEO Vm原理及其實現(xiàn)

簡介及與evm主要區(qū)別

neo vm和evm類似。底層都實現(xiàn)了一套opcode以及對應(yīng)的執(zhí)行器,opcode設(shè)計差距蠻大的,總體上來說evm的更加簡潔,neo vm的功能更加豐富強大。

  1. neo底層原生支持類型系統(tǒng),所有棧上的內(nèi)容都是有類型的,而在evm中所有的棧上內(nèi)容都是無類型的,依賴于運行時轉(zhuǎn)換。實質(zhì)上在于空間和時間的取舍。

  2. neo在opcode級別支持類型及其操作,在內(nèi)部函數(shù)調(diào)用方面evm通過jumpdest解決,neo vm的jump類指令則僅用于循環(huán),函數(shù)調(diào)用則通過call和systemcall解決(這樣很好的支持了調(diào)用函數(shù)棧)??偟膩碚fneo vm一些高級操作可以下沉到code級別執(zhí)行,方便了代碼的轉(zhuǎn)換。而evm則更加考驗編譯器的能力。

  3. 隔離執(zhí)行器和外部對象的具體實現(xiàn),vm提供了一些外部接口用于執(zhí)行一些和外部對象和存儲相關(guān)的操作。eth的外部對象和指令揉合在一起。

  4. 理論上來說eth也可以支持多種語言,實際上來說solidity一家獨大,其中未嘗沒有eth的opcode轉(zhuǎn)換難度大的原因,而neo vm的opcode則相對友好,支持多種語言開發(fā)。當(dāng)然evm也并非沒有好處,solidity支持內(nèi)聯(lián)編程,如果熟悉evm的opcode能寫出效率非常高的合約。neo在這方面尚未提供支持。

  5. neo vm支持debug,支持step into,step over,break point operation。

如需了解evm的詳細(xì)實現(xiàn)可以參考另一篇博文 https://my.oschina.net/hunjixin/blog/1805306

代碼結(jié)構(gòu)

.
├── ExecutionContext.cs   //執(zhí)行上下文 引擎,代碼,斷點
├── ExecutionEngine.cs    //執(zhí)行引擎
├── Helper.cs             //編碼及l(fā)ong型
├── ICrypto.cs            //加密解密
├── IInteropInterface.cs  //外部對象相關(guān)
├── InteropService.cs     //存儲相關(guān)
├── IScriptContainer.cs   //腳本
├── IScriptTable.cs       //腳本讀取
├── neo-vm.csproj
├── OpCode.cs             //操作碼
├── RandomAccessStack.cs  //快速訪問棧
├── ScriptBuilder.cs      //腳本構(gòu)建
├── StackItem.cs          //棧
├── Types                 //類型
│   ├── Array.cs          //數(shù)組
│   ├── Boolean.cs        //bool
│   ├── ByteArray.cs      //比特數(shù)組
│   ├── Integer.cs        //整數(shù)
│   ├── InteropInterface.cs  //操作對象接口
│   ├── Map.cs            //映射
│   └── Struct.cs         //結(jié)構(gòu)體
└── VMState.cs            //執(zhí)行狀態(tài)

類型系統(tǒng)

vm支持七種類型,分別是數(shù)組,bool,byte數(shù)組,整數(shù),外部對象,映射,結(jié)構(gòu)體。所有的結(jié)構(gòu)體都是繼承子StackItem,同時具有自己的數(shù)據(jù)字段。

stackItem

    public abstract class StackItem : IEquatable<StackItem>
    {
        public abstract bool Equals(StackItem other);

        public sealed override bool Equals(object obj)
        {
            if (obj == null) return false;
            if (obj == this) return true;
            if (obj is StackItem other)
                return Equals(other);
            return false;
        }

        public static StackItem FromInterface(IInteropInterface value)
        {
            return new InteropInterface(value);
        }

        public virtual BigInteger GetBigInteger()
        {
            return new BigInteger(GetByteArray());
        }

        public virtual bool GetBoolean()
        {
            return GetByteArray().Any(p => p != 0);
        }

        public abstract byte[] GetByteArray();

        public override int GetHashCode()
        {
            unchecked
            {
                int hash = 17;
                foreach (byte element in GetByteArray())
                    hash = hash * 31 + element;
                return hash;
            }
        }

        public virtual string GetString()
        {
            return Encoding.UTF8.GetString(GetByteArray());
        }

        public static implicit operator StackItem(int value)
        {
            return (BigInteger)value;
        }

        public static implicit operator StackItem(uint value)
        {
            return (BigInteger)value;
        }

        public static implicit operator StackItem(long value)
        {
            return (BigInteger)value;
        }

        public static implicit operator StackItem(ulong value)
        {
            return (BigInteger)value;
        }

        public static implicit operator StackItem(BigInteger value)
        {
            return new Integer(value);
        }

        public static implicit operator StackItem(bool value)
        {
            return new Boolean(value);
        }

        public static implicit operator StackItem(byte[] value)
        {
            return new ByteArray(value);
        }

        public static implicit operator StackItem(StackItem[] value)
        {
            return new Array(value);
        }

        public static implicit operator StackItem(List<StackItem> value)
        {
            return new Array(value);
        }
    }

bool 為例子

    public class Boolean : StackItem
    {
        private static readonly byte[] TRUE = { 1 };
        private static readonly byte[] FALSE = new byte[0];

        private bool value;

        public Boolean(bool value)
        {
            this.value = value;
        }

        public override bool Equals(StackItem other)
        {
            if (ReferenceEquals(this, other)) return true;
            if (ReferenceEquals(null, other)) return false;
            if (other is Boolean b) return value == b.value;
            byte[] bytes_other;
            try
            {
                bytes_other = other.GetByteArray();
            }
            catch (NotSupportedException)
            {
                return false;
            }
            return GetByteArray().SequenceEqual(bytes_other);
        }

        public override BigInteger GetBigInteger()
        {
            return value ? BigInteger.One : BigInteger.Zero;
        }

        public override bool GetBoolean()
        {
            return value;
        }

        public override byte[] GetByteArray()
        {
            return value ? TRUE : FALSE;
        }
    }

opecode

貼一些上來感受下

數(shù)值常量

    PUSH2 = 0x52, // The number 2 is pushed onto the stack.
    PUSH3 = 0x53, // The number 3 is pushed onto the stack.
    PUSH4 = 0x54, // The number 4 is pushed onto the stack.
    PUSH5 = 0x55, // The number 5 is pushed onto the stack.

跳轉(zhuǎn)

    JMP = 0x62,
    JMPIF = 0x63,
    JMPIFNOT = 0x64,

調(diào)用

    CALL = 0x65,
    RET = 0x66,
    APPCALL = 0x67,
    SYSCALL = 0x68,
    TAILCALL = 0x69,

棧操作,neo再著一塊的相對比較豐富(這里并不是全部)

    DROP = 0x75, // Removes the top stack item.
    DUP = 0x76, // Duplicates the top stack item.
    PICK = 0x79, // The item n back in the stack is copied to the top.
    ROLL = 0x7A, // The item n back in the stack is moved to the top.
    SWAP = 0x7C, // The top two items on the stack are swapped.

運算,僅貼了些代表性的上來

    INC = 0x8B, // 1 is added to the input.
    SIGN = 0x8D,
    ABS = 0x90, // The input is made positive.
    NZ = 0x92, // Returns 0 if the input is 0. 1 otherwise.
    DIV = 0x96, // a is divided by b.
    MOD = 0x97, // Returns the remainder after dividing a by b.
    SHR = 0x99, // Shifts a right b bits, preserving sign.
    BOOLAND = 0x9A, // If both a and b are not 0, the output is 1. Otherwise 0.
    GTE = 0xA2, // Returns 1 if a is greater than or equal to b, 0 otherwise.
    MAX = 0xA4, // Returns the larger of a and b.
    WITHIN = 0xA5, // Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.

加密驗證

    SHA1 = 0xA7, // The input is hashed using SHA-1.
    SHA256 = 0xA8, // The input is hashed using SHA-256.
    HASH160 = 0xA9,
    HASH256 = 0xAA,
    CHECKSIG = 0xAC,
    VERIFY = 0xAD,
    CHECKMULTISIG = 0xAE,

數(shù)組,結(jié)構(gòu)體及相關(guān)操作

    ARRAYSIZE = 0xC0,
    PACK = 0xC1,
    UNPACK = 0xC2,
    PICKITEM = 0xC3,
    SETITEM = 0xC4,
    NEWARRAY = 0xC5, //用作引用類型
    NEWSTRUCT = 0xC6, //用作值類型
    NEWMAP = 0xC7,
    APPEND = 0xC8,
    REVERSE = 0xC9,
    REMOVE = 0xCA,
    HASKEY = 0xCB,
    KEYS = 0xCC,
    VALUES = 0xCD,

異常

    THROW = 0xF0,
    THROWIFNOT = 0xF1

外部接口

腳本容器,保存當(dāng)前執(zhí)行腳本

    public interface IScriptContainer : IInteropInterface
    {
        byte[] GetMessage();
    }

合約腳本查找

    public interface IScriptTable
    {
        byte[] GetScript(byte[] script_hash);
    }

加密

    public interface ICrypto
    {
        byte[] Hash260(byte[] message);

        byte[] Hash356(byte[] message);

        bool VerifySignature(byte[] message, byte[] signature, byte[] pubkey);
    }

外部服務(wù)調(diào)用接口

    public class InteropService
    {
        private Dictionary<string, Func<ExecutionEngine, bool>> dictionary = new Dictionary<string, Func<ExecutionEngine, bool>>();

        public InteropService()
        {
            Register("System.ExecutionEngine.GetScriptContainer", GetScriptContainer);
            Register("System.ExecutionEngine.GetExecutingScriptHash", GetExecutingScriptHash);
            Register("System.ExecutionEngine.GetCallingScriptHash", GetCallingScriptHash);
            Register("System.ExecutionEngine.GetEntryScriptHash", GetEntryScriptHash);
        }

        protected void Register(string method, Func<ExecutionEngine, bool> handler)
        {
            dictionary[method] = handler;
        }

        internal bool Invoke(string method, ExecutionEngine engine)
        {
            if (!dictionary.TryGetValue(method, out Func<ExecutionEngine, bool> func)) return false;
            return func(engine);
        }

        private static bool GetScriptContainer(ExecutionEngine engine)
        {
            engine.EvaluationStack.Push(StackItem.FromInterface(engine.ScriptContainer));
            return true;
        }

        private static bool GetExecutingScriptHash(ExecutionEngine engine)
        {
            engine.EvaluationStack.Push(engine.CurrentContext.ScriptHash);
            return true;
        }

        private static bool GetCallingScriptHash(ExecutionEngine engine)
        {
            engine.EvaluationStack.Push(engine.CallingContext.ScriptHash);
            return true;
        }

        private static bool GetEntryScriptHash(ExecutionEngine engine)
        {
            engine.EvaluationStack.Push(engine.EntryContext.ScriptHash);
            return true;
        }
    }

外部對象接口

    public interface IInteropInterface
    {
    }

執(zhí)行器

    public class ExecutionEngine : IDisposable
    {
        //調(diào)用棧
        public RandomAccessStack<ExecutionContext> InvocationStack { get; } = new RandomAccessStack<ExecutionContext>();
        //執(zhí)行棧
        public RandomAccessStack<StackItem> EvaluationStack { get; } = new RandomAccessStack<StackItem>();
        //參數(shù)棧
        public RandomAccessStack<StackItem> AltStack { get; } = new RandomAccessStack<StackItem>();
        public ExecutionContext CurrentContext => InvocationStack.Peek();
        public ExecutionContext CallingContext => InvocationStack.Count > 1 ? InvocationStack.Peek(1) : null;
        public ExecutionContext EntryContext => InvocationStack.Peek(InvocationStack.Count - 1);
        //執(zhí)行狀態(tài)
        public VMState State { get; protected set; } = VMState.BREAK;

        //載入執(zhí)行腳本
        void LoadScript(byte[] script, bool push_only = false){}
        //添加斷點
        void AddBreakPoint(uint position){}
        //刪除斷點
        bool RemoveBreakPoint(uint position){}

        //執(zhí)行腳本
        void Execute(){}
        //執(zhí)行opcode
        void ExecuteOp(OpCode opcode, ExecutionContext context){}

        //執(zhí)行下一步
        void StepInto(){}
        //當(dāng)前call執(zhí)行完成
        void StepOut(){}
        //全部執(zhí)行
        void StepOver(){}
    }

操作符號執(zhí)行過程

     private void ExecuteOp(OpCode opcode, ExecutionContext context)
        {
            if (opcode > OpCode.PUSH16 && opcode != OpCode.RET && context.PushOnly)
            {
                State |= VMState.FAULT;
                return;
            }
            if (opcode >= OpCode.PUSHBYTES1 && opcode <= OpCode.PUSHBYTES75)
                EvaluationStack.Push(context.OpReader.ReadBytes((byte)opcode));
            else
                switch (opcode)
                {
                    //常量push
                    case OpCode.PUSH1:
                    case OpCode.PUSH16:
                        EvaluationStack.Push((int)opcode - (int)OpCode.PUSH1 + 1);
                        break;
                    case OpCode.JMP: //跳轉(zhuǎn)
                        {
                            int offset = context.OpReader.ReadInt16();
                            offset = context.InstructionPointer + offset - 3;
                            if (offset < 0 || offset > context.Script.Length)
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                            bool fValue = true;
                            if (opcode > OpCode.JMP)
                            {
                                fValue = EvaluationStack.Pop().GetBoolean();
                                if (opcode == OpCode.JMPIFNOT)
                                    fValue = !fValue;
                            }
                            if (fValue)
                                context.InstructionPointer = offset;
                        }
                        break;
                    case OpCode.CALL:  //和systemcall差不多, 區(qū)別在于system是系統(tǒng)預(yù)先注冊的函數(shù) call調(diào)用的是用戶自己寫的函數(shù)
                        InvocationStack.Push(context.Clone());
                        context.InstructionPointer += 2;
                        ExecuteOp(OpCode.JMP, CurrentContext);
                        break;
                    case OpCode.RET:   //退出當(dāng)前函數(shù)棧
                        InvocationStack.Pop().Dispose();
                        if (InvocationStack.Count == 0)
                            State |= VMState.HALT;
                        break;
                    case OpCode.APPCALL:  //調(diào)用外部合約
                    case OpCode.TAILCALL:
                        {
                            if (table == null)
                            {
                                State |= VMState.FAULT;
                                return;
                            }

                            byte[] script_hash = context.OpReader.ReadBytes(20);
                            if (script_hash.All(p => p == 0))
                            {
                                script_hash = EvaluationStack.Pop().GetByteArray();
                            }

                            byte[] script = table.GetScript(script_hash);
                            if (script == null)
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                            if (opcode == OpCode.TAILCALL)
                                InvocationStack.Pop().Dispose();
                            LoadScript(script);
                        }
                        break;
                    case OpCode.SYSCALL:  //內(nèi)部合約函數(shù)調(diào)用
                        if (!service.Invoke(Encoding.ASCII.GetString(context.OpReader.ReadVarBytes(252)), this))
                            State |= VMState.FAULT;
                        break;
                    case OpCode.DROP:  //移除棧頂
                        EvaluationStack.Pop();
                        break;
                    case OpCode.DUP:   //賦值棧頂  有對應(yīng)按位置復(fù)制的指令 
                        EvaluationStack.Push(EvaluationStack.Peek());
                        break;
                    case OpCode.EQUAL: //判等
                        {
                            StackItem x2 = EvaluationStack.Pop();
                            StackItem x1 = EvaluationStack.Pop();
                            EvaluationStack.Push(x1.Equals(x2));
                        }
                        break;

                    // Numeric
                    case OpCode.ABS: //運算 加減乘除 最大值最小值等等
                        {
                            BigInteger x = EvaluationStack.Pop().GetBigInteger();
                            EvaluationStack.Push(BigInteger.Abs(x));
                        }
                        break;
                    // Crypto
                    case OpCode.SHA256: //加密
                        using (SHA256 sha = SHA256.Create())
                        {
                            byte[] x = EvaluationStack.Pop().GetByteArray();
                            EvaluationStack.Push(sha.ComputeHash(x));
                        }
                        break;
                    case OpCode.CHECKSIG:  //驗證
                        {
                            byte[] pubkey = EvaluationStack.Pop().GetByteArray();
                            byte[] signature = EvaluationStack.Pop().GetByteArray();
                            try
                            {
                                EvaluationStack.Push(Crypto.VerifySignature(ScriptContainer.GetMessage(), signature, pubkey));
                            }
                            catch (ArgumentException)
                            {
                                EvaluationStack.Push(false);
                            }
                        }
                        break;
                    // Array
                    case OpCode.PICKITEM:   //數(shù)組映射取值
                        {
                            StackItem key = EvaluationStack.Pop();
                            if (key is ICollection)
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                            switch (EvaluationStack.Pop())
                            {
                                case VMArray array:
                                    int index = (int)key.GetBigInteger();
                                    if (index < 0 || index >= array.Count)
                                    {
                                        State |= VMState.FAULT;
                                        return;
                                    }
                                    EvaluationStack.Push(array[index]);
                                    break;
                                case Map map:
                                    if (map.TryGetValue(key, out StackItem value))
                                    {
                                        EvaluationStack.Push(value);
                                    }
                                    else
                                    {
                                        State |= VMState.FAULT;
                                        return;
                                    }
                                    break;
                                default:
                                    State |= VMState.FAULT;
                                    return;
                            }
                        }
                        break;
                    case OpCode.SETITEM:  //數(shù)組 映射賦值
                        {
                            StackItem value = EvaluationStack.Pop();
                            if (value is Struct s) value = s.Clone();
                            StackItem key = EvaluationStack.Pop();
                            if (key is ICollection)
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                            switch (EvaluationStack.Pop())
                            {
                                case VMArray array:
                                    int index = (int)key.GetBigInteger();
                                    if (index < 0 || index >= array.Count)
                                    {
                                        State |= VMState.FAULT;
                                        return;
                                    }
                                    array[index] = value;
                                    break;
                                case Map map:
                                    map[key] = value;
                                    break;
                                default:
                                    State |= VMState.FAULT;
                                    return;
                            }
                        }
                        break;
                    case OpCode.NEWARRAY: //創(chuàng)建數(shù)組
                        {
                            int count = (int)EvaluationStack.Pop().GetBigInteger();
                            List<StackItem> items = new List<StackItem>(count);
                            for (var i = 0; i < count; i++)
                            {
                                items.Add(false);
                            }
                            EvaluationStack.Push(new Types.Array(items));
                        }
                        break;
                    case OpCode.NEWSTRUCT: //創(chuàng)建結(jié)構(gòu)體
                        {
                            int count = (int)EvaluationStack.Pop().GetBigInteger();
                            List<StackItem> items = new List<StackItem>(count);
                            for (var i = 0; i < count; i++)
                            {
                                items.Add(false);
                            }
                            EvaluationStack.Push(new VM.Types.Struct(items));
                        }
                        break;
                    case OpCode.NEWMAP: //創(chuàng)建映射
                        EvaluationStack.Push(new Map());
                        break;
                    case OpCode.APPEND:  //追加元素
                        {
                            StackItem newItem = EvaluationStack.Pop();
                            if (newItem is Types.Struct s)
                            {
                                newItem = s.Clone();
                            }
                            StackItem arrItem = EvaluationStack.Pop();
                            if (arrItem is VMArray array)
                            {
                                array.Add(newItem);
                            }
                            else
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                        }
                        break;
                    case OpCode.REMOVE:  //移除元素
                        {
                            StackItem key = EvaluationStack.Pop();
                            if (key is ICollection)
                            {
                                State |= VMState.FAULT;
                                return;
                            }
                            switch (EvaluationStack.Pop())
                            {
                                case VMArray array:
                                    int index = (int)key.GetBigInteger();
                                    if (index < 0 || index >= array.Count)
                                    {
                                        State |= VMState.FAULT;
                                        return;
                                    }
                                    array.RemoveAt(index);
                                    break;
                                case Map map:
                                    map.Remove(key);
                                    break;
                                default:
                                    State |= VMState.FAULT;
                                    return;
                            }
                        }
                        break;
                    case OpCode.KEYS:  //獲取映射鍵集合,對應(yīng)的還有獲取值集合 haskey
                        switch (EvaluationStack.Pop())
                        {
                            case Map map:
                                EvaluationStack.Push(new VMArray(map.Keys));
                                break;
                            default:
                                State |= VMState.FAULT;
                                return;
                        }
                        break;

                    // Exceptions
                    case OpCode.THROW: //異常中止
                        State |= VMState.FAULT;
                        return;
                    case OpCode.THROWIFNOT:
                        if (!EvaluationStack.Pop().GetBoolean())
                        {
                            State |= VMState.FAULT;
                            return;
                        }
                        break;

                    default:
                        State |= VMState.FAULT;
                        return;
                }
            if (!State.HasFlag(VMState.FAULT) && InvocationStack.Count > 0)
            {
                //斷點起效的位置
                if (CurrentContext.BreakPoints.Contains((uint)CurrentContext.InstructionPointer))
                    State |= VMState.BREAK;
            }
        }

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI