NEO VM原理及其实现


声明:本文转载自https://my.oschina.net/hunjixin/blog/1812516,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

NEO Vm原理及其实现

简介及与evm主要区别

neo vm和evm类似。底层都实现了一套opcode以及对应的执行器,opcode设计差距蛮大的,总体上来说evm的更加简洁,neo vm的功能更加丰富强大。

  1. neo底层原生支持类型系统,所有栈上的内容都是有类型的,而在evm中所有的栈上内容都是无类型的,依赖于运行时转换。实质上在于空间和时间的取舍。

  2. neo在opcode级别支持类型及其操作,在内部函数调用方面evm通过jumpdest解决,neo vm的jump类指令则仅用于循环,函数调用则通过call和systemcall解决(这样很好的支持了调用函数栈)。总的来说neo vm一些高级操作可以下沉到code级别执行,方便了代码的转换。而evm则更加考验编译器的能力。

  3. 隔离执行器和外部对象的具体实现,vm提供了一些外部接口用于执行一些和外部对象和存储相关的操作。eth的外部对象和指令揉合在一起。

  4. 理论上来说eth也可以支持多种语言,实际上来说solidity一家独大,其中未尝没有eth的opcode转换难度大的原因,而neo vm的opcode则相对友好,支持多种语言开发。当然evm也并非没有好处,solidity支持内联编程,如果熟悉evm的opcode能写出效率非常高的合约。neo在这方面尚未提供支持。

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

如需了解evm的详细实现可以参考另一篇博文 https://my.oschina.net/hunjixin/blog/1805306

代码结构

. ├── ExecutionContext.cs   //执行上下文 引擎,代码,断点 ├── ExecutionEngine.cs    //执行引擎 ├── Helper.cs             //编码及long型 ├── ICrypto.cs            //加密解密 ├── IInteropInterface.cs  //外部对象相关 ├── InteropService.cs     //存储相关 ├── IScriptContainer.cs   //脚本 ├── IScriptTable.cs       //脚本读取 ├── neo-vm.csproj ├── OpCode.cs             //操作码 ├── RandomAccessStack.cs  //快速访问栈 ├── ScriptBuilder.cs      //脚本构建 ├── StackItem.cs          //栈 ├── Types                 //类型 │   ├── Array.cs          //数组 │   ├── Boolean.cs        //bool │   ├── ByteArray.cs      //比特数组 │   ├── Integer.cs        //整数 │   ├── InteropInterface.cs  //操作对象接口 │   ├── Map.cs            //映射 │   └── Struct.cs         //结构体 └── VMState.cs            //执行状态 

类型系统

vm支持七种类型,分别是数组,bool,byte数组,整数,外部对象,映射,结构体。所有的结构体都是继承子StackItem,同时具有自己的数据字段。

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

贴一些上来感受下

数值常量

    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. 

跳转

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

调用

    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, 

数组,结构体及相关操作

    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 

外部接口

脚本容器,保存当前执行脚本

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

合约脚本查找

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

加密

    public interface ICrypto     {         byte[] Hash160(byte[] message);          byte[] Hash256(byte[] message);          bool VerifySignature(byte[] message, byte[] signature, byte[] pubkey);     } 

外部服务调用接口

    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     {     } 

执行器

    public class ExecutionEngine : IDisposable     {         //调用栈         public RandomAccessStack<ExecutionContext> InvocationStack { get; } = new RandomAccessStack<ExecutionContext>();         //执行栈         public RandomAccessStack<StackItem> EvaluationStack { get; } = new RandomAccessStack<StackItem>();         //参数栈         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);         //执行状态         public VMState State { get; protected set; } = VMState.BREAK;          //载入执行脚本         void LoadScript(byte[] script, bool push_only = false){}         //添加断点         void AddBreakPoint(uint position){}         //删除断点         bool RemoveBreakPoint(uint position){}          //执行脚本         void Execute(){}         //执行opcode         void ExecuteOp(OpCode opcode, ExecutionContext context){}          //执行下一步         void StepInto(){}         //当前call执行完成         void StepOut(){}         //全部执行         void StepOver(){}     } 

操作符号执行过程

     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: //跳转                         {                             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差不多, 区别在于system是系统预先注册的函数 call调用的是用户自己写的函数                         InvocationStack.Push(context.Clone());                         context.InstructionPointer += 2;                         ExecuteOp(OpCode.JMP, CurrentContext);                         break;                     case OpCode.RET:   //退出当前函数栈                         InvocationStack.Pop().Dispose();                         if (InvocationStack.Count == 0)                             State |= VMState.HALT;                         break;                     case OpCode.APPCALL:  //调用外部合约                     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:  //内部合约函数调用                         if (!service.Invoke(Encoding.ASCII.GetString(context.OpReader.ReadVarBytes(252)), this))                             State |= VMState.FAULT;                         break;                     case OpCode.DROP:  //移除栈顶                         EvaluationStack.Pop();                         break;                     case OpCode.DUP:   //赋值栈顶  有对应按位置复制的指令                          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:   //数组映射取值                         {                             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:  //数组 映射赋值                         {                             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: //创建数组                         {                             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: //创建结构体                         {                             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: //创建映射                         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:  //获取映射键集合,对应的还有获取值集合 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;             }         } 

参考

neo vm: https://github.com/neo-project/neo-vm

本文发表于2018年05月15日 06:00
(c)注:本文转载自https://my.oschina.net/hunjixin/blog/1812516,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1537 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1