NEO VM原理及其实现(转载)
NEO Vm原理及其实现
简介及与evm主要区别
neo vm和evm类似。底层都实现了一套opcode以及对应的执行器,opcode设计差距蛮大的,总体上来说evm的更加简洁,neo vm的功能更加丰富强大。
neo底层原生支持类型系统,所有栈上的内容都是有类型的,而在evm中所有的栈上内容都是无类型的,依赖于运行时转换。实质上在于空间和时间的取舍。
neo在opcode级别支持类型及其操作,在内部函数调用方面evm通过jumpdest解决,neo vm的jump类指令则仅用于循环,函数调用则通过call和systemcall解决(这样很好的支持了调用函数栈)。总的来说neo vm一些高级操作可以下沉到code级别执行,方便了代码的转换。而evm则更加考验编译器的能力。
隔离执行器和外部对象的具体实现,vm提供了一些外部接口用于执行一些和外部对象和存储相关的操作。eth的外部对象和指令揉合在一起。
理论上来说eth也可以支持多种语言,实际上来说solidity一家独大,其中未尝没有eth的opcode转换难度大的原因,而neo vm的opcode则相对友好,支持多种语言开发。当然evm也并非没有好处,solidity支持内联编程,如果熟悉evm的opcode能写出效率非常高的合约。neo在这方面尚未提供支持。
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 != );
- }
- public abstract byte[] GetByteArray();
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = ;
- foreach (byte element in GetByteArray())
- hash = hash * + 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 = { };
- private static readonly byte[] FALSE = new byte[];
- 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 > ? InvocationStack.Peek() : null;
- public ExecutionContext EntryContext => InvocationStack.Peek(InvocationStack.Count - );
- //执行状态
- 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 + );
- break;
- case OpCode.JMP: //跳转
- {
- int offset = context.OpReader.ReadInt16();
- offset = context.InstructionPointer + offset - ;
- if (offset < || 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 += ;
- ExecuteOp(OpCode.JMP, CurrentContext);
- break;
- case OpCode.RET: //退出当前函数栈
- InvocationStack.Pop().Dispose();
- if (InvocationStack.Count == )
- State |= VMState.HALT;
- break;
- case OpCode.APPCALL: //调用外部合约
- case OpCode.TAILCALL:
- {
- if (table == null)
- {
- State |= VMState.FAULT;
- return;
- }
- byte[] script_hash = context.OpReader.ReadBytes();
- if (script_hash.All(p => p == ))
- {
- 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()), 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 < || 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 < || 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 = ; 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 = ; 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 < || 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 > )
- {
- //断点起效的位置
- if (CurrentContext.BreakPoints.Contains((uint)CurrentContext.InstructionPointer))
- State |= VMState.BREAK;
- }
- }
转载自 https://my.oschina.net/hunjixin/blog/1812516
NEO VM原理及其实现(转载)的更多相关文章
- JAVA CAS原理深度分析-转载
参考文档: http://www.blogjava.net/xylz/archive/2010/07/04/325206.html http://blog.hesey.net/2011/09/reso ...
- NET/ASP.NET Routing路由(深入解析路由系统架构原理)(转载)
NET/ASP.NET Routing路由(深入解析路由系统架构原理) 阅读目录: 1.开篇介绍 2.ASP.NET Routing 路由对象模型的位置 3.ASP.NET Routing 路由对象模 ...
- JMeter使用中遇到的问题:Jmeter Debug - "Unrecognized VM option '+HeapDumpOnOutOfMemoryError"(转载)
转载自 http://www.cnblogs.com/yangxia-test 启动JMeter.bat的程序时,出现以下出错信息: Unrecognized VM option '+HeapDump ...
- mysql 索引原理及查询优化 -转载
转载自 mysql 索引原理及查询优化 https://www.cnblogs.com/panfb/p/8043681.html 潘红伟 mysql 索引原理及查询优化 一 介绍 为何要有索引? ...
- Redis集群的原理和搭建(转载)
转载来源:https://www.jianshu.com/p/c869feb5581d Redis集群的原理和搭建 前言 Redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得 ...
- 深入浅出Java并发包—CountDownLauch原理分析 (转载)
转载地址:http://yhjhappy234.blog.163.com/blog/static/3163283220135875759265/ CountDownLauch是Java并发包中的一个同 ...
- JPEG原理详解 (转载)
JPEG算法解密 by jinchao 图片压缩有多重要,可能很多人可能并没有一个直观上的认识,举个例子,一张800X800大小的普通图片,如果未经压缩,大概在1.7MB左右,这个体积如果存放文本 ...
- 弱类型变量原理探究(转载 http://www.csdn.net/article/2014-09-15/2821685-exploring-of-the-php)
N首页> 云计算 [问底]王帅:深入PHP内核(一)——弱类型变量原理探究 发表于2014-09-19 09:00| 13055次阅读| 来源CSDN| 36 条评论| 作者王帅 问底PHP王帅 ...
- DPM(Deformable Parts Model)--原理(一)(转载)
DPM(Deformable Parts Model) Reference: Object detection with discriminatively trained partbased mode ...
随机推荐
- 数据标准化+网格搜索+交叉验证+预测(Python)
Download datasets iris_training.csv from:https://github.com/tensorflow/tensorflow/tree/master/tensor ...
- 一、I/O操作(File文件对象)
一.File类 Java里,文件和文件夹都是用File代表 1.使用绝对路径或者相对路径创建File对象 使用绝对路径或者相对路径创建File对象 package File; import java. ...
- Linux安装配置NFS教程(CentOS 6.5)
一.服务端安装nfs 1.1安装 yum install -y rpcbind yum install -y nfs-utils 1.2配置nfs共享目录 这里以/nfs目录为例 mkdir /nfs ...
- java 常用命令
#查看堆使用情况jmap -heap [pid]#查看占用内存高的对象jmap -histo:live [pid] | head -n 100#查看占用内存高的对象,dump成文件,线下分析jmap ...
- 码云git使用一(上传本地项目到码云git服务器上)
主要讲下如果将项目部署到码云git服务器上,然后使用studio导入git项目,修改本地代码后,并同步到码云git上面. 首先:我们在码云上注册账号并登陆.官网(https://git.oschina ...
- python ctrl+c
#!/usr/bin/env pythonimport signalimport sysimport osdef signal_handler(signal, frame): print('You p ...
- windows中mysql5.7保存emoji表情
1.找到my.ini文件,修改一下配置: [client] default-character-set=utf8mb4 [mysqld] character-set-client-handshake ...
- 输出前n大的数(分治)
描述:给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输 出. 输入: 第一行包含一个整数n,表示数组的大小.n < 100000.第二行包含n个整数,表示数组的元素,整数之间以一 ...
- AI工具(矩形工具)(椭圆工具的操作与矩形类似)(剪切蒙版)5.11
矩形工具:按住SHIFT键,可以绘制一个正方形. 按住ALT键,可以绘制以落点为中心的矩形. 同时按住SHIFT和ALT键可以绘制以鼠标落点为中心的正方形. 选择矩形工具,点击页面,输入高宽,精确绘制 ...
- SQL 常用判断语句
我们在做sql更新时,为防止sql重复执行报错,需要对所需要执行的对象进行判断是否存在: 常用判断脚本如下: 判断视图是否存在 IF object_id('viewname') IS not NULL ...