Skip to content

Latest commit

 

History

History
1009 lines (785 loc) · 46.1 KB

README.md

File metadata and controls

1009 lines (785 loc) · 46.1 KB

Neo Virtual Machine

NeoVM is a lightweighted, general-purpose virtual machine that executes Neo smart contract code. The concept of virtual machine described in this paadper is in narrow sense, it's not a simulation of physical machine by operating system. Unlike VMware or Hyper-V, it's mainly aimed at specific usage.

For example, in JVM or CLR of .Net, source code will be compiled into relevant bytecodes, and be executed on the corresponding virtual machine. JVM or CLR will read instructions, decode, execute and write results back. Those steps are very similar to the concepts on real physical machines. The binary instructions are still running on the physical machine. It takes instructions from memory and transmits them to the CPU through the bus, then decodes, executes and stores the results.

Changes in NEO3

  • ADD

  • DELETE

    • APPCALL, TAILCALL, SHA1, SHA256, HASH160, HASH256, CHECKSIG, VERIFY, CHECKMULTISIG, CALL_I, CALL_E, CALL_ED, CALL_ET, CALL_EDT

NeoVM Architecture

nvm

The graph above is the system architecture of NeoVM, which includes execution engine, memory, interoperable services.

A complete operation process is as follows:

  1. Compile the smart contract source codes into bytecodes.

  2. Push the bytecodes and related parameters as a running context into the InvocationStack.

  3. Each time the execution engine takes a instruction from the current context, it executes the instruction, and stores the data in the evaluation stack (EvaluationStack) and temporary stack (AltStack) of current context.

  4. It uses the interoperable service if it needs to access external data.

  5. After all scripts are executed, the results will be saved in the ResultStack.

Execution Engine

The left part of the graph above is the virtual machine's execution engine(equivalent to CPU). It can execute common instructions such as flow control, stack operation, bit operation, arithmetic operation, logical operation, cryptography, etc. It can also interact with the interoperable services through system call. NeoVM has four states: NONE, HALT, FAULT, BREAK.

  • NONE is a normal state.

  • HALT is a stopped state. When the InvocationStack is empty, it means all scripts are executed, the virtual machine's state will be set to HALT.

  • FAULT is an error state. When something goes wrong with an operation, the virtual machine's state will be set to FAULT.

  • BREAK is an interrupted state and is used in the debugging process of smart contract generally.

Each time before the virtual machine starts, the execution engine will detect the virtual machine's state, and only when the state is NONE, can it start running.

Temporary Storage

NeoVM uses stacks as its temporary storage. NeoVM has four types of stacks: InvocationStack, EvaluationStack, AltStack and ResultStack.

  • InvocationStack: is used to store all execution contexts of current NeoVM, which are isolated from each other in the stack. Context switching is performed based on the current context and entry context. The current context points to the top element of invocation stack, which is ExecutionContext0 in the architecture figure. And the entry context points to the tail element of the invocation stack, which is ExecutionContextN in the architecture figure
  • EvaluationStack is for storing the data used by the instruction in the execution process. Each execution context has its evaluation stack
  • AltStack is for storing the temporary data used by the instruction in the execution process. Each execution context has its alt stack
  • ResultStack is used to store execution results after all scripts are executed.

Interoperable service layer

The right part of the graph above is the virtual machine's interoperable service layer, which provides API for smart contract to access data on the blockchain. By using these API, smart contract can access information in a block , information in a transaction, and information of an asset.

In addition, the interoperable service layer provides a persistent storage for each contract. Each Neo contract can declare to have a private storage to save information in form of key-value pair optionally when the contract is created. When a smart contract invocate another smart contract, the storage are separated. The smart contract being invoked has it's own persistent storage. If the caller contract needs the contract being invoked to access data of the caller contract, it needs to pass its own storage context to the callee (authorization) before the callee can perform the read-write operation.

The detail of interoperable services are describled in the "Smart Contract" section.

Built-in data types

NeoVM has seven built-in data types:

Type Description
Boolean Implemented as two byte arrays, TRUE and FALSE.
Integer Implemented as a BigInteger value.
ByteArray Implemented as a byte array.
Array Implemented as a List<StackItem>, the StackItem is an abstract class, and all the built-in data types are inherited from it.
Struct Inherited from Array, a Clone method is added and Equals method is overridden.
Map Implemented as a key-value pair Dictionary<StackItem, StackItem>.
InteropInterface Interoperable interface
// boolean type
private static readonly byte[] TRUE = { 1 };
private static readonly byte[] FALSE = new byte[0];

private bool value;

Instructions

NeoVM has implemented 173 instructions. The categories are as follows:

Contrant Flow Control Stack Operation String Operation Logical Operation Arithmetic Operation Advanced Data Structure Exception Processing
98 7 17 5 5 25 14 2

Contrant

The constant instructions mainly complete the function of pushing constants or arrays into the EvaluationStack.

PUSH0

Instruction PUSH0
Bytecode: 0x00
Alias: PUSHF
Fee: 0.00000030 GAS
Function: Push an empty array into the EvaluationStack

PUSHBYTES

Instruction PUSHBYTES1~PUSHBYTES75
Bytecode: 0x01~0x4B
Fee: 0.00000120 GAS
Function: Push a byte array into the EvaluationStack, the length of which is equal to the value of this instruction's bytecode.

PUSHDATA

Instruction PUSHDATA1, PUSHDATA2, PUSHDATA4
Bytecode: 0x4C, 0x4D, 0x4E
Fee: 0.00000180 GAS, 0.00013000 GAS, 0.00110000 GAS
Function: Push a byte array into the EvaluationStack, the length of which is specified by 1|2|4 bytes after this instruction.

PUSHNULL

Instruction PUSHNULL
Bytecode 0x50
Fee: 0.00000030 GAS
Function: Push NULL value into the EvaluationStack.

PUSHM1

Instruction PUSHM1
Bytecode: 0x4F
Fee: 0.00000030 GAS
Function: Push a BigInteger of -1 into the EvaluationStack.

PUSHN

Instruction PUSH1~PUSH16
Bytecode: 0x51~0x60
Alias: PUSHT is an alias for PUSH1
Fee: 0.00000030 GAS
Function: Push a BigInteger into the EvaluationStack, the value of which is equal to 1~16.

Flow Control

It's used to control the running process of NeoVM, including jump, call and other instructions.

NOP

Instruction NOP
Bytecode: 0x61
Fee: 0.00000030 GAS
Function: Empty operation, but will add 1 to the instruction counter.

JMP

Instruction JMP
Bytecode: 0x62
Fee: 0.00000070 GAS
Function: Jump to the specified offset unconditionally, which is specified by 2 bytes after this instruction.

JMPIF

Instruction JMPIF
Bytecode: 0x63
Fee: 0.00000070 GAS
Function: When the top element of the EvaluationStack isn't 0, then jump to the specified offset, which is specified by 2 bytes after this instruction.
Whether the condition determines true or not, the top element of the stack will be removed.

JMPIFNOT

Instruction JMPIFNOT
Bytecode: 0x64
Fee: 0.00000070 GAS
Function: When the top element of the EvaluationStack is 0, then jump to the specified offset, which is specified by 2 bytes after this instruction.

CALL

Instruction CALL
Bytecode: 0x65
Fee: 0.00022000 GAS
Function: Call the function at the specified offset, which is specified by 2 bytes after this instruction.

RET

Instruction RET
Bytecode: 0x66
Fee: 0.00000040 GAS
Function: Remove the top element of the InvocationStack and set the instruction counter point to the next frame of the stack.
If the InvocationStack is empty, the virtual machine enters HALT state.

SYSCALL

Instruction SYSCALL
Bytecode: 0x68
Fee: According to the specific interoperable service billing of the system call, refer to Interop Service Fees
Function: Call the specified interoperable function whose name is specified by the string after this instruction.

Stack Operation

Copy, remove and swap the elements of the stack.

DUPFROMALTSTACKBOTTOM

added in NEO3

Instruction DUPFROMALTSTACKBOTTOM
Bytecode: 0x69
Fee: 0.00000060 GAS
Function: Copy the bottom element of the AltStack, and push it into the EvaluationStack .

DUPFROMALTSTACK

Instruction DUPFROMALTSTACK
Bytecode: 0x6A
Fee: 0.00000060 GAS
Function: Copy the top element of the AltStack, and push it into the EvaluationStack .

TOALTSTACK

Instruction TOALTSTACK
Bytecode: 0x6B
Fee: 0.00000060 GAS
Function: Remove the top element of the EvaluationStack, and push it into the AltStack.

FROMALTSTACK

Instruction FROMALTSTACK
Bytecode: 0x6C
Fee: 0.00000060 GAS
Function: Remove the top element of the AltStack, and push it into the EvaluationStack.

ISNULL

Instruction ISNULL
Bytecode 0x70
Fee: 0.00000060 GAS
Function Return true if the input is NULL; otherwise, return false

XDROP

Instruction XDROP
Bytecode: 0x6D
Fee: 0.00000400 GAS
Function: Remove the element n at the top of the EvaluationStack, and remove the remaining element with index n.
Input: Xn Xn-1 ... X2 X1 X0 n
Output: Xn-1 ... X2 X1 X0

XSWAP

Instruction XSWAP
Bytecode: 0x72
Fee: 0.0000006 GAS
Function: Remove the element n at the top of the EvaluationStack, and swap the remaining element with index 0 and the element with index n.
Input: Xn Xn-1 ... X2 X1 X0 n
Output: X0 Xn-1 ... X2 X1 Xn

XTUCK

Instruction XTUCK
Bytecode: 0x73
Fee: 0.000004 GAS
Function: Remove the element n at the top of the EvaluationStack, copy the element with index 0, and insert to the index n.
Input: Xn Xn-1 ... X2 X1 X0 n
Output: Xn X0 Xn-1 ... X2 X1 X0

DEPTH

Instruction DEPTH
Bytecode: 0x74
Fee: 0.0000006 GAS
Function: Push the numbe of elements in the EvaluationStack into the top of the EvaluationStack.

DROP

Instruction DROP
Bytecode: 0x75
Fee: 0.0000006 GAS
Function: Remove the top element of the EvaluationStack

DUP

Instruction DUP
Bytecode: 0x76
Fee: 0.0000006 GAS
Function: Copy the top element of the EvaluationStack, and push it into the EvaluationStack.
Input: X
Output: X X

NIP

Instruction NIP
Bytecode: 0x77
Fee: 0.0000006 GAS
Function: Remove the second top element of the EvaluationStack
Input: X1 X0
Output: X0

OVER

Instruction OVER
Bytecode: 0x78
Fee: 0.0000006 GAS
Function: Copy the second top element of the EvaluationStack, and push it into the EvaluationStack.
Input: X1 X0
Output: X1 X0 X1

PICK

Instruction PICK
Bytecode: 0x79
Fee: 0.0000006 GAS
Function: Remove the element n at the top of the EvaluationStack, and copy the element with index n to the top.
Input: Xn Xn-1 ... X2 X1 X0 n
Output: Xn Xn-1 ... X2 X1 X0 Xn

ROLL

Instruction ROLL
Bytecode: 0x7A
Fee: 0.000004 GAS
Function: Remove the element n at the top of the EvaluationStack, and move the element with index n to the top.
Input: Xn Xn-1 ... X2 X1 X0 n
Output: Xn-1 ... X2 X1 X0 Xn

ROT

Instruction ROT
Bytecode: 0x7B
Fee: 0.0000006 GAS
Function: Move the third top element of the EvaluationStack to the top.
Input: X2 X1 X0
Output: X1 X0 X2

SWAP

Instruction SWAP
Bytecode: 0x7C
Fee: 0.0000006 GAS
Function: Swap the two elements at the top of the EvaluationStack
Input: X1 X0
Output: X0 X1

TUCK

Instruction TUCK
Bytecode: 0x7D
Fee: 0.0000006 GAS
Function: Copy the top element of the EvaluationStack, and insert to the index 2.
Input: X1 X0
Output: X0 X1 X0

String Operation

CAT

Instruction CAT
Bytecode: 0x7E
Fee: 0.0008 GAS
Function: Remove the two top elements of the EvaluationStack, concat them together and push it back to the EvaluationStack
Input: X1 X0
Output: Concat(X1,X0)

SUBSTR

Instruction SUBSTR
Bytecode: 0x7F
Fee: 0.0008 GAS
Function: Remove the three top elements of the EvaluationStack, calculate the substring and push it back.
Input: X index len
Output: SubString(X,index,len)

LEFT

Instruction LEFT
Bytecode: 0x80
Fee: 0.0008 GAS
Function: Remove the two top elements of the EvaluationStack, calculate the left-side substring and push it back.
Input: X len
Output: Left(X,len)

RIGHT

Instruction RIGHT
Bytecode: 0x81
Fee: 0.0008 GAS
Function: Remove the two top elements of the EvaluationStack, calculate the right-side substring and push it back.
Input: X len
Output: Right(X,len)

SIZE

Instruction SIZE
Bytecode: 0x82
Fee: 0.0000006 GAS
Function: Push the length of the top string element to the EvaluationStack top.
Input: X
Output: X len(X)

Logical Operation

INVERT

Instruction INVERT
Bytecode: 0x83
Fee: 0.000001 GAS
Function: Remove the top element, inverse by bit, and push it back to the EvaluationStack top.
Input: X
Output: ~X

AND

Instruction AND
Bytecode: 0x84
Fee: 0.000002 GAS
Function: Remove the two top elements, push the logic AND result of the two elements back to the EvaluationStack top.
Input: AB
Output: A&B

OR

Instruction OR
Bytecode: 0x85
Fee: 0.000002 GAS
Function: Remove the two top elements, push the logic OR result of the two elements back to the EvaluationStack top.
Input: AB
Output: A|B

XOR

Instruction XOR
Bytecode: 0x86
Fee: 0.000002 GAS
Function: Remove the two top elements, push the logic XOR result of the two elements back to the EvaluationStack top.
Input: AB
Output: A^B

EQUAL

Instruction EQUAL
Bytecode: 0x87
Fee: 0.000002 GAS
Function: Check whether the top two elements are equivalence bit-by-bit.
Input: AB
Output: Equals(A,B)

Arithmetic Operation

INC

Instruction INC
Bytecode: 0x8B
Fee: 0.000001 GAS
Function: Add 1 to the top element of the EvaluationStack.
Input: X
Output: X+1

DEC

Instruction DEC
Bytecode: 0x8C
Fee: 0.000001 GAS
Function: Add -1 to the top element of the EvaluationStack.
Input: X
Output: X-1

SIGN

Instruction SIGN
Bytecode: 0x8D
Fee: 0.000001 GAS
Function: Remove the top element and push the sign of it back to the EvaluationStack.
Input: X
Output: X.Sign()

NEGATE

Instruction NEGATE
Bytecode: 0x8F
Fee: 0.000001 GAS
Function: Remove the top element and push the opposite number back to the EvaluationStack.
Input: X
Output: -X

ABS

Instruction ABS
Bytecode: 0x90
Fee: 0.000001 GAS
Function: Remove the top element and push the absolute number back to the EvaluationStack.
Input: X
Output: Abs(X)

NOT

Instruction NOT
Bytecode: 0x91
Fee: 0.000001 GAS
Function: Remove the top element and push the logic "negation" value back to the EvaluationStack.
Input: X
Output: !X

NZ

Instruction NZ
Bytecode: 0x92
Fee: 0.000001 GAS
Function: Check whether the top element of the EvaluationStack is a non-zero value.
Input: X
Output: X!=0

ADD

Instruction ADD
Bytecode: 0x93
Fee: 0.000002 GAS
Function: The addition operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A+B

SUB

Instruction SUB
Bytecode: 0x94
Fee: 0.000002 GAS
Function: The subtraction operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A-B

MUL

Instruction MUL
Bytecode: 0x95
Fee: 0.000003 GAS
Function: The multiplication operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A*B

DIV

Instruction DIV
Bytecode: 0x96
Fee: 0.000003 GAS
Function: The division operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A/B

MOD

Instruction MOD
Bytecode: 0x97
Fee: 0.000003 GAS
Function: The redundancy operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A%B

SHL

Instruction SHL
Bytecode: 0x98
Fee: 0.000003 GAS
Function: The left-shift operation is performed on the top elment of the EvaluationStack.
Instruction Xn
Bytecode: X<<n

SHR

Instruction SHR
Bytecode: 0x99
Fee: 0.000003 GAS
Function: The right-shift operation is performed on the top elment of the EvaluationStack.
Input: Xn
Output: X>>n

BOOLAND

Instruction BOOLAND
Bytecode: 0x9A
Fee: 0.000002 GAS
Function: The logic "and" operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A&&B

BOOLOR

Instruction BOOLOR
Bytecode: 0x9D
Fee: 0.000002 GAS
Function: The logic "or" operation is performed on the top two elments of the EvaluationStack.
Input: AB
Output: A||B

NUMEQUAL

Instruction NUMEQUAL
Bytecode: 0x9C
Fee: 0.000002 GAS
Function: Check whether the top two Bitintegers of the EvaluationStack are equal.
Input: AB
Output: A==B

NUMNOTEQUAL

Instruction NUMNOTEQUAL
Bytecode: 0x9E
Fee: 0.000002 GAS
Function: Check whether the top two Bitintegers of the EvaluationStack aren't equal.
Input: AB
Output: A!=B

LT

Instruction LT
Bytecode: 0x9F
Fee: 0.000002 GAS
Function: Check whether the first top element is less than the second top element in the EvaluationStack.
Input: AB
Output: A<B

GT

Instruction GT
Bytecode: 0xA0
Fee: 0.000002 GAS
Function: Check whether the first top element is more than the second top element in the EvaluationStack.
Input: AB
Output: A>B

LTE

Instruction LTE
Bytecode: 0xA1
Fee: 0.000002 GAS
Function: Check whether the first top element ls less than or equal to the second top element in the EvaluationStack.
Input: AB
Output: A<=B

GTE

Instruction GTE
Bytecode: 0xA2
Fee: 0.000002 GAS
Function: Check whether the first top element is more than or equal to the second top element in the EvaluationStack.
Input: AB
Output: A>=B

MIN

Instruction MIN
Bytecode: 0xA3
Fee: 0.000002 GAS
Function: Calculate the minimum of the two top elements in the EvaluationStack.
Input: AB
Output: Min(A,B)

MAX

Instruction MAX
Bytecode: 0xA4
Fee: 0.000002 GAS
Function: Calculate the maximum of the two top elements in the EvaluationStack.
Input: AB
Output: Max(A,B)

WITHIN

Instruction WITHIN
Bytecode: 0xA5
Fee: 0.000002 GAS
Function: Check whether the Biginteger value is within the specified range.
Input: XAB
Output: A<=X&&X<B

Advanced Data Structure

It has implemented common operations for array, map, struct, etc.

ARRAYSIZE

Instruction ARRAYSIZE
Bytecode: 0xC0
Fee: 0.0000015 GAS
Function: Get the number of elements of the array at the top of the EvaluationStack.
Input: [X0 X1 X2 ... Xn-1]
Output: n

PACK

Instruction PACK
Bytecode: 0xC1
Fee: 0.00007GAS
Function: Pack the n elments at the top of the EvaluationStack into array.
Input: Xn-1 ... X2 X1 X0 n
Output: [X0 X1 X2 ... Xn-1]

UNPACK

Instruction UNPACK
Bytecode: 0xC2
Fee: 0.00007 GAS
Function: Get the number of elements of the array at the top of the EvaluationStack.
Input: [X0 X1 X2 ... Xn-1]
Output: Xn-1 ... X2 X1 X0 n

PICKITEM

Instruction PICKITEM
Bytecode: 0xC3
Fee: 0.0027 GAS
Function: Get the specified element in the array at the top of the EvaluationStack.
Input: [X0 X1 X2 ... Xn-1] i
Output: Xi

SETITEM*

Instruction SETITEM
Bytecode: 0xC4
Fee: 0.0027 GAS
Function: Assign a value to the specified index element in the array at the top of the EvaluationStack.
Input: [X0 X1 X2 ... Xn-1] I V
Output: [X0 X1 X2 Xi-1 V X i+1 ... Xn-1]

NEWARRAY

Instruction NEWARRAY
Bytecode: 0xC5
Fee: 0.00015 GAS
Function: Create a new N-size array on the top of the EvaluationStack.
Input: n
Output: Array(n) with all false elements.

NEWSTRUCT

Instruction NEWSTRUCT
Bytecode: 0xC6
Fee: 0.00015 GAS
Function: Create a new N-size struct on the top of the EvaluationStack.
Input: n
Output: Struct(n) with all false elements.

NEWMAP

Instruction NEWMAP
Bytecode: 0xC7
Fee: 0.000002 GAS
Function: Create a new map on the top of the EvaluationStack.
Input:
Output: Map()

APPEND*

Instruction APPEND
Bytecode: 0xC8
Fee: 0.00015 GAS
Function: Add a new item to the array
Input: Array item
Output: Array.add(item)

REVERSE*

Instruction REVERSE
Bytecode: 0xC9
Fee: 0.000005 GAS
Function: Reverse the array.
Input: [X0 X1 X2 ... Xn-1]
Output: [Xn-1 ... X2 X1 X0]

REMOVE*

Instruction REMOVE
Bytecode: 0xCA
Fee: 0.000005 GAS
Function: Remove the specified element from the array or map.
Input: [X0 X1 X2 ... Xn-1] m
Output: [X0 X1 X2 ... Xm-1 Xm+1 ... Xn-1]

HASKEY

Instruction HASKEY
Bytecode: 0xCB
Fee: 0.0027 GAS
Function: Check whether the array or the map contains a specified key element.
Input: [X0 X1 X2 ... Xn-1] key
Output: true or false

KEYS

Instruction KEYS
Bytecode: 0xCC
Fee: 0.000005 GAS
Function: Get all the keys of the map, and put them into a new array.
Input: Map
Output: [key1 key2 ... key n]

VALUES

Instruction VALUES
Bytecode: 0xCD
Fee: 0.00007 GAS
Function: Get all the values of the array or the map, and put them into a new array.
Input: Map or Array
Output: [Value1 Value2... Value n]

Exception Processing

THROW

Instruction THROW
Bytecode: 0xF0
Fee: 0.0000003 GAS
Function: Set the virtual machine state to FAULT

THROWIFNOT

Instruction THROWIFNOT
Bytecode: 0xF1
Fee: 0.0000003 GAS
Function: Read a boolean value from the top of the stack, and if it's False, then set the virtual machine state to FAULT.

Note: The operation code with * indicates that the result of the operation is not pushed back to the EvaluationStack.

Click here to see the Chinese edition of the NeoVM