您好,登錄后才能下訂單哦!
NEO VM原理及其實現(xiàn)是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
neo vm和evm類似。底層都實現(xiàn)了一套opcode以及對應(yīng)的執(zhí)行器,opcode設(shè)計差距蠻大的,總體上來說evm的更加簡潔,neo vm的功能更加豐富強大。
neo底層原生支持類型系統(tǒng),所有棧上的內(nèi)容都是有類型的,而在evm中所有的棧上內(nèi)容都是無類型的,依賴于運行時轉(zhuǎn)換。實質(zhì)上在于空間和時間的取舍。
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則更加考驗編譯器的能力。
隔離執(zhí)行器和外部對象的具體實現(xiàn),vm提供了一些外部接口用于執(zhí)行一些和外部對象和存儲相關(guān)的操作。eth的外部對象和指令揉合在一起。
理論上來說eth也可以支持多種語言,實際上來說solidity一家獨大,其中未嘗沒有eth的opcode轉(zhuǎn)換難度大的原因,而neo vm的opcode則相對友好,支持多種語言開發(fā)。當(dāng)然evm也并非沒有好處,solidity支持內(nèi)聯(lián)編程,如果熟悉evm的opcode能寫出效率非常高的合約。neo在這方面尚未提供支持。
neo vm支持debug,支持step into,step over,break point operation。
如需了解evm的詳細(xì)實現(xiàn)可以參考另一篇博文 https://my.oschina.net/hunjixin/blog/1805306
. ├── 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)
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; } }
貼一些上來感受下
數(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 { }
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è)資訊頻道,感謝您對億速云的支持。
免責(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)容。