Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the principle and implementation of NEO VM

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

NEO VM principle and its implementation is how, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain for you in detail, people with this need can come to learn, I hope you can gain something.

A brief introduction to the principle and implementation of NEO Vm and its main differences from evm

Neo vm is similar to evm. The bottom layer has implemented a set of opcode and corresponding executors, opcode design gap is quite large, generally speaking, evm is more concise, neo vm functions are more rich and powerful.

The underlying neo natively supports the type system, where all content on the stack is typed, while all content on the stack in evm is untyped, depending on run-time conversion. In essence, it lies in the choice between space and time.

Neo supports types and their operations at the opcode level, evm solves internal function calls through jumpdest, neo vm's jump instructions are only used for loops, and function calls are resolved through call and systemcall (which well supports calling function stacks). In general, some advanced operations of neo vm can be sank to the code level, which facilitates code conversion. On the other hand, evm tests the ability of the compiler.

Isolating implementations of executors and external objects, vm provides external interfaces for performing operations related to external objects and storage. The external objects and instructions of eth are mixed together.

Theoretically, eth can also support multiple languages, but in fact, solidity is the only one, which is difficult to convert without eth's opcode, while neo vm's opcode is relatively friendly and supports multi-language development. Of course, evm is not without benefits, solidity supports inline programming, if familiar with evm opcode can write very efficient contracts. Neo has not yet provided support in this regard.

Neo vm supports debug and step into,step over,break point operation.

To learn more about the implementation of evm, you can refer to another blog post, https://my.oschina.net/hunjixin/blog/1805306

Code structure. ├── ExecutionContext.cs / / execution context engine, code Breakpoint ├── ExecutionEngine.cs / / execution engine ├── Helper.cs / / Encoding and long ├── ICrypto.cs / / encryption and decryption ├── IInteropInterface.cs / / external object related ├── InteropService.cs / / Storage related ├── IScriptContainer.cs / / script ├── IScriptTable.cs / / script read ├── neo-vm.csproj ├── OpCode .cs / / opcode ├── RandomAccessStack.cs / / Quick access stack ├── ScriptBuilder.cs / / script to build ├── StackItem.cs / / stack ├── Types / / type │ ├── Array.cs / / array │ ├── Boolean.cs / / bool │ ├── ByteArray.cs / / Bit array │ ├── Integer.cs / / Integer │ ├── InteropInterface.cs / / Operand interface │ ├── Map.cs / / Mapping │ └── Struct.cs / / struct └── VMState.cs / / execution status type system

Vm supports seven types, namely arrays, bool,byte arrays, integers, external objects, mappings, and structures. All structures are inherited child StackItem and have their own data fields.

StackItem

Public abstract class StackItem: IEquatable {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 value) {return new Array (value);}}

Bool as an example

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

Post some and feel it.

Numerical constant

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.

Jump

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

Call

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

Stack operation, neo is relatively rich in another piece (not all here)

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.

Operation, only some representative ones are posted.

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, / / an 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 an and b are not 0, the output is 1.Otherwise 0. GTE = 0xA2, / / Returns 1 if an is greater than or equal to b, 0 otherwise. MAX = 0xA4, / / Returns the larger of an and b. WITHIN = 0xA5, / / Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.

Encryption verification

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

Arrays, structures and related operations

ARRAYSIZE = 0xC0, PACK = 0xC1, UNPACK = 0xC2, PICKITEM = 0xC3, SETITEM = 0xC4, NEWARRAY = 0xC5, / / used as reference type NEWSTRUCT = 0xC6, / / used as value type NEWMAP = 0xC7, APPEND = 0xC8, REVERSE = 0xC9, REMOVE = 0xCA, HASKEY = 0xCB, KEYS = 0xCC, VALUES = 0xCD

Abnormal

THROW = 0xF0, THROWIFNOT = 0xF1 external interface

Script container, saving the currently executed script

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

Contract script lookup

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

Encrypt

Public interface ICrypto {byte [] Hash260 (byte [] message); byte [] Hash356 (byte [] message); bool VerifySignature (byte [] message, byte [] signature, byte [] pubkey);}

External service invocation interface

Public class InteropService {private Dictionary dictionary = new Dictionary (); 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 handler) {dictionary [method] = handler;} internal bool Invoke (string method, ExecutionEngine engine) {if (! dictionary.TryGetValue (method, out Func 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;}}

External object interface

Public interface IInteropInterface {} executor public class ExecutionEngine: IDisposable {/ / call stack public RandomAccessStack InvocationStack {get;} = new RandomAccessStack (); / execution stack public RandomAccessStack EvaluationStack {get;} = new RandomAccessStack (); / / parameter stack public RandomAccessStack AltStack {get;} = new RandomAccessStack (); public ExecutionContext CurrentContext = > InvocationStack.Peek (); public ExecutionContext CallingContext = > InvocationStack.Count > 1? InvocationStack.Peek (1): null; public ExecutionContext EntryContext = > InvocationStack.Peek (InvocationStack.Count-1); / / execution status public VMState State {get; protected set;} = VMState.BREAK / / load execution script void LoadScript (byte [] script, bool push_only = false) {} / / add breakpoint void AddBreakPoint (uint position) {} / / remove breakpoint bool RemoveBreakPoint (uint position) {} / / execute script void Execute () {} / / execute opcode void ExecuteOp (OpCode opcode) ExecutionContext context) {} / / execute the next step void StepInto () {} / / the current call execution completes void StepOut () {} / / all execute void StepOver () {}}

Operation symbol execution process

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 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: / / is similar to systemcall, except that system is a pre-registered function of the system. Call calls the user-written function InvocationStack.Push (context.Clone ()); context.InstructionPointer + = 2; ExecuteOp (OpCode.JMP, CurrentContext); break. Case OpCode.RET: / / exit the current function stack InvocationStack.Pop () .Dispose (); if (InvocationStack.Count = = 0) State | = VMState.HALT; break Case OpCode.APPCALL: / / call external contract 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: / / Internal contract function calls if (! service.Invoke (Encoding.ASCII.GetString (context.OpReader.ReadVarBytes (252), this)) State | = VMState.FAULT; break Case OpCode.DROP: / / remove EvaluationStack.Pop () at the top of the stack; break; case OpCode.DUP: / / there is an instruction EvaluationStack.Push (EvaluationStack.Peek ()) that is copied by location at the top of the assignment stack; break Case OpCode.EQUAL: / / judgment {StackItem x2 = EvaluationStack.Pop (); StackItem x1 = EvaluationStack.Pop (); EvaluationStack.Push (x1.Equals (x2));} break / / Numeric case OpCode.ABS: / / Operation addition, subtraction, multiplication, division, maximum, minimum, etc. {BigInteger x = EvaluationStack.Pop () .GetBigInteger (); EvaluationStack.Push (BigInteger.Abs (x)) } break; / / Crypto case OpCode.SHA256: / / encrypt using (SHA256 sha = SHA256.Create ()) {byte [] x = EvaluationStack.Pop () .GetByteArray () EvaluationStack.Push (sha.ComputeHash (x));} break; case OpCode.CHECKSIG: / / verify {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: / / Array mapping values {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 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: / / array map assignment {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: / / create the array {int count = (int) EvaluationStack.Pop () .GetBigInteger () List items = new List (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 items = new List(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: / / get the set of mapping keys, corresponding to the set of get values haskey switch (EvaluationStack.Pop ()) {case Map map: EvaluationStack.Push (new VMArray (map.Keys)) Break; default: State | = VMState.FAULT; return;} break / / Exceptions case OpCode.THROW: / / abnormal abort 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) {/ / where the breakpoint takes effect if (CurrentContext.BreakPoints.Contains ((uint) CurrentContext.InstructionPointer)) State | = VMState.BREAK;}} is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report