Skip to content

[Reference Purpose, No Need for Review] Neo Virtual Machine (NeoVM) Specification #3811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Jim8y opened this issue Mar 7, 2025 · 6 comments

Comments

@Jim8y
Copy link
Contributor

Jim8y commented Mar 7, 2025

No description provided.

@Jim8y Jim8y added Discussion Initial issue state - proposed but not yet accepted Work in Progress and removed Discussion Initial issue state - proposed but not yet accepted labels Mar 7, 2025
@Jim8y
Copy link
Contributor Author

Jim8y commented Mar 7, 2025

Neo Virtual Machine (NeoVM) Specification (N3 V3.8)

Version: 1.0
Status: Draft
Last Updated: 2025-03-08

This document is the a specification for the Neo Virtual Machine (NeoVM). It defines all required behaviors and constraints for compliant implementations.

Executive Summary

The Neo Virtual Machine (NeoVM) is a lightweight, cross-platform virtual machine optimized for blockchain smart contracts. This specification provides a complete and formal definition of the Neo VM architecture, semantics, and implementation requirements.

Key Features

NeoVM offers the following powerful capabilities:

  1. Comprehensive type system with formal verification
  2. Efficient reference counting algorithm
  3. Robust exception handling capabilities
  4. Seamless interoperability with host environment

VM Architecture at a Glance

Note: The diagram below is ASCII art and displays best with a monospace font.

┌───────────────────────────────────────────────────────────────┐
│                     Host Environment                          │
└───────────────────────────────────────────────────────────────┘
                           ▲
                           │ Interop Interface
                           ▼
┌───────────────────────────────────────────────────────────────┐
│                  Interoperability Layer                       │
└───────────────────────────────────────────────────────────────┘
                           ▲
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│                     Execution Layer                           │
└───────────────────────────────────────────────────────────────┘
                           ▲
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│                    Type System Layer                          │
└───────────────────────────────────────────────────────────────┘
                           ▲
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│                      Core VM Layer                            │
└───────────────────────────────────────────────────────────────┘

Comparison with Other Blockchain VMs

Feature NeoVM Ethereum VM WebAssembly VM
Memory Model Reference Counting Stack/Memory Linear Memory
Type System Rich (10+ types) Limited (256-bit) Basic Types
Control Flow Advanced (TRY/CATCH) Basic Advanced
Native Types Arbitrary Integers 256-bit 32/64-bit
Collections Arrays, Maps, Structs No direct support Tables
Exception Handling Yes No Traps

Key Differences from Previous Versions

NeoVM v3.0 introduces several improvements over previous versions:

  1. Enhanced type system with formal verification
  2. More efficient reference counting algorithm
  3. Expanded exception handling capabilities
  4. Improved interoperability with host environment

Who Should Read This Document

This specification is intended for:

  • VM implementers creating compliant NeoVM implementations
  • Smart contract developers writing Neo contracts
  • Security researchers analyzing the VM semantics
  • Tool developers building development environments

1. Introduction

1.1 Purpose

This document defines the formal specification for the Neo Virtual Machine (NeoVM), the execution environment for smart contracts on the Neo blockchain. This specification establishes the normative requirements for implementing a compliant NeoVM.

1.2 Scope

This specification covers:

  • Architecture and core components
  • Type system and data representation
  • Execution model and state transitions
  • Complete instruction set with formal semantics
  • Execution limits and verification rules
  • Integration requirements with blockchain environments

1.3 Conformance

A conforming implementation of NeoVM MUST adhere to all REQUIRED behaviors specified in this document. Items marked as RECOMMENDED or OPTIONAL may be implemented at the discretion of the implementer.

1.4 Normative References

  1. ISO/IEC 23271:2012 - Common Language Infrastructure (CLI), Partitions I to VI
  2. IEEE 754-2019 - Standard for Floating-Point Arithmetic
  3. Neo N3 Blockchain Protocol Specification
  4. RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels
  5. FIPS PUB 180-4 - Secure Hash Standard (SHS)
  6. FIPS PUB 186-4 - Digital Signature Standard (DSS)
  7. ANSI X9.62-2005 - Public Key Cryptography for the Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
  8. Automated Formal Verification of Smart Contracts, Zheng Yang, Hang Lei (2020)
  9. Neo Smart Contract Developer Guide, Neo Foundation (2023)
  10. NeoContract White Paper, Erik Zhang (2018)

1.5 Terminology and Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

1.5.1 Glossary of Key Terms

Term Definition
Bytecode The binary instruction format executed by the NeoVM
Context An execution frame containing state for a script invocation
Evaluation Stack Stack structure used for operands and results during execution
Instruction A single operation in the VM with an opcode and optional operands
Interoperability The capability to communicate with the host environment
Invocation Stack Stack of execution contexts representing the call hierarchy
Script A sequence of bytecode instructions to be executed
Stack Item A typed value that can be placed on the evaluation stack
Static Field Data storage that persists across multiple invocations of the same script

1.6 Formal Notation

This specification uses the following formal notation techniques to precisely define the behavior of the Neo VM:

1.6.1 Operational Semantics

Note for GitHub Comments: The formal semantics in this document use Unicode symbols (σ, μ, ι) and special notation (⊢, ⟨, ⟩, ⟹) which may not display correctly in all GitHub contexts. When copying parts of this document to GitHub comments, consider replacing these with ASCII alternatives.

Small-step operational semantics are used to formally specify state transitions in the VM. The general form is:

          conditions/premises
------------------------------------ [Rule-Name]
           conclusion/result

Where:

  • Conditions describe when the rule applies
  • The conclusion describes the resulting state change
  • [Rule-Name] identifies the specific rule

1.6.2 Mathematical Notation

The following notation is used throughout the specification:

  • VM State: The complete state of the virtual machine at any point in execution

  • Memory State: The current state of memory including all allocated objects

  • Instruction Pointer: The current position in the bytecode being executed

  • Evaluation Stack: The stack of values being operated on by instructions

  • Stack elements are represented as [first, second, ..., last] where "last" is the top of the stack

  • S' represents the stack after an operation is performed

  • State transitions show how the VM moves from one state to another after executing instructions

1.6.3 Functions and Predicates

  • type(x) returns the type of value x
  • size(x) returns the size of value x in bytes
  • valid(σ) is true if the VM state σ is valid
  • isA(x, T) is true if value x is of type T or can be converted to type T

1.7 Document Organization

This specification is organized into the following main sections:

  1. Introduction: Overview, purpose, and conventions (current section)
  2. Architecture: Core components and design principles
  3. Type System: Data types and operations
  4. Execution Model: Execution model and state transitions
  5. Instruction Set: Complete operation specifications
  6. Engine Limits: Execution constraints and security measures
  7. Conformance Testing: Validation procedures
  8. Appendices: Additional reference material including bytecode reference, glossary, and file formats

Each section builds on previous ones, with cross-references provided where relevant.

2. Architecture

2.1 Design Principles

The NeoVM architecture adheres to the following principles:

  1. Stack-Based Execution: NeoVM MUST operate as a stack machine, where operands are pushed onto and popped from an evaluation stack.

  2. Determinism: For a given input and execution state, a NeoVM implementation MUST produce identical outputs across different environments, platforms, and implementations.

  3. Isolation: The execution environment MUST be isolated from the host system, with explicit interoperability channels defined via system calls.

  4. Resource Constraint: The VM MUST enforce resource limits (memory usage, execution cycles, stack depth) to prevent denial of service attacks.

2.2 System Architecture

The NeoVM architecture consists of the following component layers:

  1. Core VM Layer: Provides the fundamental virtual machine mechanisms
  2. Execution Layer: Manages bytecode execution and control flow
  3. Type System Layer: Defines and enforces data types and operations
  4. Interoperability Layer: Facilitates communication with the host environment

4.1.2 Instruction Set Architecture

The NeoVM instruction set is structured as follows:

┌─────────────────────────────────────────────────────────────┐
│                 INSTRUCTION SET ARCHITECTURE                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │   Instruction │      │  Type Conversion│                │
│   │   Decoding    │◄────►│     System      │                │
│   └───────┬───────┘      └─────────────────┘                │
│           │                                                 │
│           ▼                                                 │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │    Type       │      │     Equality    │                │
│   │ Implementations│◄────►│     System     │                │
│   └───────┬───────┘      └─────────────────┘                │
│           │                                                 │
│           ▼                                                 │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │   Reference   │      │    Memory       │                │
│   │   Counting    │◄────►│   Management    │                │
│   └───────────────┘      └─────────────────┘                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Figure 4.1: Instruction Set Architecture

4.2 Instruction Types

A conforming implementation MUST support the following instruction types:

4.2.1 Control Flow Instructions

Control flow instructions allow for conditional execution and looping.

Opcode Mnemonic Description Stack Effect
0x00 NOP No operation 0
0x01 JMP Unconditional jump -1
0x02 JMPIF Conditional jump if true -1
0x03 JMPIFNOT Conditional jump if false -1
0x04 CALL Call a subroutine +1
0x05 RET Return from a subroutine -1
0x06 APPCALL Call a contract +1
0x07 SYSCALL Call a native method +1
0x08 ABORT Abort the execution 0
0x09 ASSERT Assert a condition -1
0x0A THROW Throw an error -1
0x0B THROWIFNOT Throw an error if false -1

4.2.2 Stack Manipulation Instructions

Stack manipulation instructions allow for pushing, popping, and duplicating values on the stack.

Opcode Mnemonic Description Stack Effect
0x0C PUSHINT8 Push a byte as an integer +1
0x0D PUSHINT16 Push a short as an integer +1
0x0E PUSHINT32 Push an integer +1
0x0F PUSHINT64 Push a long as an integer +1
0x10 PUSHINT128 Push a big integer +1
0x11 PUSHINT256 Push a huge integer +1
0x12 PUSHBYTES Push a byte array +1
0x13 PUSHDATA Push a data structure +1
0x14 PUSHNULL Push a null value +1
0x15 PUSHDATA1 Push a byte array of variable length +1
0x16 PUSHDATA2 Push a byte array of variable length +1
0x17 PUSHDATA4 Push a byte array of variable length +1
0x18 PUSHM1 Push -1 +1
0x19 PUSH0 Push 0 +1
0x1A PUSH1 Push 1 +1
0x1B PUSH2 Push 2 +1
0x1C PUSH3 Push 3 +1
0x1D PUSH4 Push 4 +1
0x1E PUSH5 Push 5 +1
0x1F PUSH6 Push 6 +1
0x20 PUSH7 Push 7 +1
0x21 PUSH8 Push 8 +1
0x22 PUSH9 Push 9 +1
0x23 PUSH10 Push 10 +1
0x24 PUSH11 Push 11 +1
0x25 PUSH12 Push 12 +1
0x26 PUSH13 Push 13 +1
0x27 PUSH14 Push 14 +1
0x28 PUSH15 Push 15 +1
0x29 PUSH16 Push 16 +1
0x2A POP Pop the top stack item -1
0x2B NIP Remove the second-to-top stack item -1
0x2C XDROP Drop N items from the stack -N
0x2D XSWAP Swap N items on the stack 0
0x2E TUCK Copy the second-to-top stack item to the top +1
0x2F OVER Copy the second stack item to the top +1
0x30 PICK Copy the Nth stack item to the top +1
0x31 ROLL Rotate the top N stack items 0
0x32 ROT Rotate the top 3 stack items 0
0x33 DUP Duplicate the top stack item +1
0x34 DEPTH Get the current stack depth +1
0x35 DROP Discard the top stack item -1
0x36 INVERT Bitwise NOT the top stack item 0
0x37 AND Bitwise AND the top two stack items -1
0x38 OR Bitwise OR the top two stack items -1
0x39 XOR Bitwise XOR the top two stack items -1
0x3A EQUAL Compare the top two stack items for equality -1
0x3B NOT Logical NOT the top stack item 0
0x3C NZ Check if the top stack item is non-zero 0
0x3D INC Increment the top stack item 0
0x3E DEC Decrement the top stack item 0
0x3F SIGN Get the sign of the top stack item 0
0x40 NEGATE Negate the top stack item 0
0x41 ABS Get the absolute value of the top stack item 0
0x42 NOP1 No operation (1-byte opcode) 0
0x43 NOP2 No operation (2-byte opcode) 0
0x44 NOP3 No operation (3-byte opcode) 0
0x45 NOP4 No operation (4-byte opcode) 0
0x46 NOP5 No operation (5-byte opcode) 0
0x47 NOP6 No operation (6-byte opcode) 0
0x48 NOP7 No operation (7-byte opcode) 0
0x49 NOP8 No operation (8-byte opcode) 0
0x4A NOP9 No operation (9-byte opcode) 0
0x4B NOP10 No operation (10-byte opcode) 0

4.2.3 Arithmetic Instructions

Arithmetic instructions allow for basic arithmetic operations on the stack.

Opcode Mnemonic Description Stack Effect
0x4C ADD Add the top two stack items -1
0x4D SUB Subtract the top two stack items -1
0x4E MUL Multiply the top two stack items -1
0x4F DIV Divide the top two stack items -1
0x50 MOD Get the remainder of the top two stack items -1
0x51 SHL Shift the top stack item left by N bits 0
0x52 SHR Shift the top stack item right by N bits 0
0x53 NOT Bitwise NOT the top stack item 0
0x54 BOOLAND Logical AND the top two stack items -1
0x55 BOOLOR Logical OR the top two stack items -1
0x56 NUMEQUAL Compare the top two stack items for numerical equality -1
0x57 NUMNOTEQUAL Compare the top two stack items for numerical inequality -1
0x58 LT Check if the second stack item is less than the top stack item -1
0x59 GT Check if the second stack item is greater than the top stack item -1
0x5A LTE Check if the second stack item is less than or equal to the top stack item -1
0x5B GTE Check if the second stack item is greater than or equal to the top stack item -1
0x5C MIN Get the minimum of the top two stack items -1
0x5D MAX Get the maximum of the top two stack items -1
0x5E WITHIN Check if the second stack item is within the range of the top two stack items -2

4.2.4 Static Field Instructions

Static field instructions allow for loading and storing data in static fields.

Opcode Mnemonic Description Stack Effect
0x5F LDSFLD Load static field at index +1
0x60 STSFLD0 Store to static field 0 -1
0x61 STSFLD1 Store to static field 1 -1
0x62 STSFLD2 Store to static field 2 -1
0x63 STSFLD3 Store to static field 3 -1
0x64 STSFLD4 Store to static field 4 -1

4.2.5 Array Instructions

Array instructions allow for manipulating arrays on the stack.

Opcode Mnemonic Description Stack Effect
0x65 ARRAYSIZE Get the size of the top array 0
0x66 PACK Pack multiple stack items into an array -N
0x67 UNPACK Unpack an array into multiple stack items +N
0x68 PICKITEM Get the Nth item from the top array 0
0x69 SETITEM Set the Nth item of the second array to the top stack item -3
0x6A NEWARRAY Create a new array with N items +1
0x6B NEWSTRUCT Create a new struct with N fields +1
0x6C NEWMAP Create a new map +1
0x6D APPEND Append an item to the top array -1
0x6E REVERSEITEMS Reverse the order of items in the top array 0
0x6F REMOVE Remove the Nth item from the top array -1
0x70 HASKEY Check if a key exists in the top map -1
0x71 KEYS Get the keys of the top map 0
0x72 VALUES Get the values of the top map 0
0x73 ITEMS Get the items of the top map 0
0x74 CLEARITEMS Clear all items from the top array or map 0

4.2.6 Execution Flow Instructions

Execution flow instructions allow for controlling the execution flow of the VM.

Opcode Mnemonic Description Stack Effect
0x21 NOP No operation 0
0x22 JMP Jump to a target instruction (1-byte offset) 0
0x23 JMP_L Jump to a target instruction (4-byte offset) 0
0x24 JMPIF Jump if the value is true (1-byte offset) -1
0x25 JMPIF_L Jump if the value is true (4-byte offset) -1
0x26 JMPIFNOT Jump if the value is false (1-byte offset) -1
0x27 JMPIFNOT_L Jump if the value is false (4-byte offset) -1
0x28 JMPEQ Jump if two values are equal (1-byte offset) -2
0x29 JMPEQ_L Jump if two values are equal (4-byte offset) -2
0x2A JMPNE Jump if two values are not equal (1-byte offset) -2
0x2B JMPNE_L Jump if two values are not equal (4-byte offset) -2
0x2C JMPGT Jump if first value is greater than second value (1-byte offset) -2
0x2D JMPGT_L Jump if first value is greater than second value (4-byte offset) -2
0x2E JMPGE Jump if first value is greater than or equal to second value (1-byte offset) -2
0x2F JMPGE_L Jump if first value is greater than or equal to second value (4-byte offset) -2
0x30 JMPLT Jump if first value is less than second value (1-byte offset) -2
0x31 JMPLT_L Jump if first value is less than second value (4-byte offset) -2
0x32 JMPLE Jump if first value is less than or equal to second value (1-byte offset) -2
0x33 JMPLE_L Jump if first value is less than or equal to second value (4-byte offset) -2
0x34 CALL Call a function at target address (1-byte offset) Varies
0x35 CALL_L Call a function at target address (4-byte offset) Varies
0x36 CALLA Call a function using address from stack Varies
0x37 CALLT Call a function using token Varies
0x38 ABORT Abort execution 0
0x39 ASSERT Assert that condition is true -1
0x3A THROW Throw an exception -1
0x3B THROWIFNOT Throw an error if false -1

4.2.7 Type Operations Instructions

Type operations instructions allow for checking types and performing type conversions.

Opcode Mnemonic Description Stack Effect
0xD8 ISNULL Returns true if the input is null; false otherwise 0
0xD9 ISTYPE Returns true if the top item is of the specified type; false otherwise 0
0xDB CONVERT Converts the top item to the specified type 0

4.2.8 Slot Instructions

Slot instructions allow for accessing and manipulating slot values.

Opcode Mnemonic Description Stack Effect
0x42 INITSLOT Initialize the slot with the specified number of local and argument slots 0
0x43 LDLOC Load a local variable onto the stack +1
0x44 STLOC Store the top stack item to a local variable -1
0x45 LDARG Load an argument onto the stack +1
0x46 STARG Store the top stack item to an argument -1
0x47 LDSFLD Load a static field onto the stack +1
0x48 STSFLD Store the top stack item to a static field -1
0x49 LDLOC0 Load local variable 0 onto the stack +1
0x4A LDLOC1 Load local variable 1 onto the stack +1
0x4B LDLOC2 Load local variable 2 onto the stack +1
0x4C LDLOC3 Load local variable 3 onto the stack +1
0x4D LDLOC4 Load local variable 4 onto the stack +1
0x4E LDLOC5 Load local variable 5 onto the stack +1
0x4F LDLOC6 Load local variable 6 onto the stack +1

4.2.9 Stack Operations Instructions

Stack operations instructions allow for manipulating local variables and arguments.

Opcode Mnemonic Description Stack Effect
0x50 LDLOC7 Load local variable 7 onto the stack +1
0x51 LDLOC8 Load local variable 8 onto the stack +1
0x52 LDLOC9 Load local variable 9 onto the stack +1
0x53 LDARG0 Load argument 0 onto the stack +1
0x54 LDARG1 Load argument 1 onto the stack +1
0x55 LDARG2 Load argument 2 onto the stack +1
0x56 LDARG3 Load argument 3 onto the stack +1
0x57 LDARG4 Load argument 4 onto the stack +1
0x58 LDARG5 Load argument 5 onto the stack +1
0x59 LDARG6 Load argument 6 onto the stack +1
0x5A STLOC0 Store the top stack item to local variable 0 -1
0x5B STLOC1 Store the top stack item to local variable 1 -1
0x5C STLOC2 Store the top stack item to local variable 2 -1
0x5D STLOC3 Store the top stack item to local variable 3 -1
0x5E STLOC4 Store the top stack item to local variable 4 -1
0x5F STLOC5 Store the top stack item to local variable 5 -1
0x60 STLOC6 Store the top stack item to local variable 6 -1
0x61 STLOC7 Store the top stack item to local variable 7 -1
0x62 STLOC8 Store the top stack item to local variable 8 -1
0x63 STLOC9 Store the top stack item to local variable 9 -1
0x64 STARG0 Store the top stack item to argument 0 -1
0x65 STARG1 Store the top stack item to argument 1 -1
0x66 STARG2 Store the top stack item to argument 2 -1
0x67 STARG3 Store the top stack item to argument 3 -1
0x68 STARG4 Store the top stack item to argument 4 -1
0x69 STARG5 Store the top stack item to argument 5 -1
0x6A STARG6 Store the top stack item to argument 6 -1

4.2.10 Array and Collection Instructions

Array and collection instructions allow for manipulating arrays, maps, and other collections.

Opcode Mnemonic Description Stack Effect
0x6B NEWARRAY Create a new array with the specified number of elements 0
0x6C NEWARRAY_T Create a new array with the specified element type 0
0x6D NEWSTRUCT Create a new struct with the specified number of fields 0
0x6E NEWMAP Create a new map +1
0x6F NEWDICT Create a new dictionary +1
0x70 SIZE Get the size of an array, string, or map 0
0x71 HASKEY Check if a key exists in a map or dictionary -1
0x72 KEYS Get all keys from a map or dictionary 0
0x73 VALUES Get all values from a map or dictionary 0
0x74 PICKITEM Get an item from an array, string, map, or struct -1
0x75 APPEND Append an item to an array -2
0x76 SETITEM Set an item in an array, map, or struct -3
0x77 REVERSEITEMS Reverse the items in an array -1
0x78 REMOVE Remove an item from an array, map, or dictionary -1
0x79 CLEARITEMS Clear all items from an array, map, or dictionary -1
0xC4 POPITEM Pop an item from an array -1

4.2.11 Arithmetic Instructions

Arithmetic instructions allow for performing arithmetic operations.

Opcode Mnemonic Description Stack Effect
0x80 SIGN Get the sign of a number 0
0x81 ABS Get the absolute value of a number 0
0x82 NEGATE Negate a number 0
0x83 INC Increment a number by 1 0
0x84 DEC Decrement a number by 1 0
0x85 ADD Add two numbers -1
0x86 SUB Subtract two numbers -1
0x87 MUL Multiply two numbers -1
0x88 DIV Divide two numbers -1
0x89 MOD Get the remainder of a division -1
0x8A POW Raise a number to a power -1
0x8B SQRT Get the square root of a number 0
0x8C SHL Shift left -1
0x8D SHR Shift right -1
0x8E NOT Bitwise NOT 0
0x8F AND Bitwise AND -1
0x90 OR Bitwise OR -1
0x91 XOR Bitwise XOR -1
0x92 EQUAL Check if two values are equal -1
0x93 NOTEQUAL Check if two values are not equal -1
0x94 LESSTHAN Check if the first value is less than the second -1
0x95 LESSTHANOREQUAL Check if the first value is less than or equal to the second -1
0x96 GREATERTHAN Check if the first value is greater than the second -1
0x97 GREATERTHANOREQUAL Check if the first value is greater than or equal to the second -1
0x98 MIN Get the minimum of two values -1
0x99 MAX Get the maximum of two values -1
0x9A WITHIN Check if a value is within a range -2
0x9B PACK Pack multiple values into an array Varies
0x9C UNPACK Unpack an array into multiple values Varies
0x9D NEWBUFFER Create a new buffer 0
0x9E MEMCPY Copy memory from one buffer to another -3
0x9F CAT Concatenate two strings or buffers -1
0xA0 SUBSTR Get a substring -2
0xA1 LEFT Get the leftmost characters of a string -1
0xA2 RIGHT Get the rightmost characters of a string -1

4.3 Instruction Execution

The NeoVM instruction execution model is as follows:

Figure 2: Neo VM State Transition Diagram

  1. From the NONE state, the VM MAY transition to:

    • HALT (successful completion)
    • FAULT (error condition)
    • BREAK (breakpoint hit, for debugging implementations)
  2. From the BREAK state, the VM MAY transition back to:

    • NONE (when execution resumes)
  3. Once in the HALT or FAULT state, the VM MUST NOT transition to any other state without a complete reset and reinitialization.

2.4.2 State Indicators

A compliant VM implementation MUST provide a mechanism to query the current execution state, which MUST return one of the enumerated state values defined above.

3. Type System

3.1 Type System Overview

The NeoVM type system provides the data types and operations required for smart contract execution. It is designed to balance expressiveness, safety, and determinism.

3.1.1 Design Requirements

The NeoVM type system MUST:

  1. Support deterministic execution with identical results across all platforms.
  2. Prevent type-related memory safety issues through strict type checking.
  3. Provide both value semantics and reference semantics where appropriate.
  4. Support controlled type conversion between compatible types.
  5. Enable complex data structures required for smart contract development.

3.1.2 Type System Architecture

The NeoVM type system is structured as follows:

┌─────────────────────────────────────────────────────────────┐
│                   TYPE SYSTEM ARCHITECTURE                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │   StackItem   │      │  Type Conversion│                │
│   │   Interface   │◄────►│     System      │                │
│   └───────┬───────┘      └─────────────────┘                │
│           │                                                 │
│           ▼                                                 │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │    Type       │      │     Equality    │                │
│   │ Implementations│◄────►│     System     │                │
│   └───────┬───────┘      └─────────────────┘                │
│           │                                                 │
│           ▼                                                 │
│   ┌───────────────┐      ┌─────────────────┐                │
│   │   Reference   │      │    Memory       │                │
│   │   Counting    │◄────►│   Management    │                │
│   └───────────────┘      └─────────────────┘                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Figure 3.1: Type System Architecture

3.2 Stack Item Types

A conforming implementation MUST support the following fundamental data types, identified by their type code:

Type Code Type Name Description Value Semantics Example Usage
0x00 Any Represents any type; used for type conversion operations No Type checking, generic handling
0x10 Pointer Represents a code pointer for VM-internal jump operations No Jump tables, function pointers
0x20 Boolean Represents boolean values (true/false) Yes Conditionals, flags
0x21 Integer Represents arbitrary-precision integer numbers Yes Arithmetic, counting, identifiers
0x28 ByteString Represents an immutable sequence of bytes Yes Hashes, keys, addresses, constants
0x30 Buffer Represents a mutable sequence of bytes No Building strings, byte manipulation
0x40 Array Represents an ordered collection of items with reference semantics No Lists, sequences, collections
0x41 Struct Represents a structure of items with value semantics (deep-copy) No Compound data, value objects
0x48 Map Represents a collection of key-value pairs with hash-based lookup No Dictionaries, property bags
0x60 InteropInterface Represents an interface to external services No Blockchain services, native contracts

3.2.1 Type Hierarchy Visualization

The following diagram illustrates the hierarchical relationship between Neo VM types:

┌──────────────────────────────────────────────────────────────────────────────┐
│                           NEO VM TYPE HIERARCHY                              │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│                               ┌─────────────┐                                │
│                               │  StackItem  │                                │
│                               │ (Interface) │                                │
│                               └──────┬──────┘                                │
│                                      │                                       │
│      ┌───────────────┬───────────────┼────────────────┬───────────────┐      │
│      │               │               │                │               │      │
│ ┌────┴─────┐ ┌───────┴───────┐ ┌─────┴─────┐ ┌────────┴───────┐ ┌─────┴────┐ │
│ │ Null     │ │ PrimitiveType │ │ ByteSeq   │ │  CompoundType  │ │ Special  │ │
│ │ (0x00)   │ └───────┬───────┘ └─────┬─────┘ └────────┬───────┘ │ Types    │ │
│ └──────────┘         │               │                │         │          │ │
│               ┌──────┴──────┐ ┌──────┴─────┐  ┌───────┼───────┐ │          │ │
│               │ Boolean     │ │ ByteString │  │ Array │ Struct│ │          │ │
│               │ (0x20)      │ │ (0x28)     │  │(0x40) │(0x41) │ │          │ │
│               └─────────────┘ ├─────────────┤ └───────┴───────┘ │          │ │
│               ┌─────────────┐ │ Buffer      │ ┌───────────────┐ │          │ │
│               │ Integer     │ │ (0x30)      │ │ Map           │ │          │ │
│               │ (0x21)      │ └─────────────┘ │ (0x48)        │ │          │ │
│               └─────────────┘                 └───────────────┘ │          │ │
│                                                                 ├──────────┤ │
│                                                                 │ Pointer  │ │
│                                                                 │ (0x10)   │ │
│                                                                 ├──────────┤ │
│                                                                 │ Interop  │ │
│                                                                 │ (0x60)   │ │
│                                                                 └──────────┘ │
│                                                                              │
│ Type Characteristics:                                                        │
│                                                                              │
│ ┌───────────────────────────┐ ┌─────────────────────────────────────────┐    │
│ │ Null (0x00)               │ │ • Singleton instance                    │    │
│ │                           │ │ • Equals() only true for itself         │    │
│ └───────────────────────────┘ └─────────────────────────────────────────┘    │
│                                                                              │
│ ┌───────────────────────────┐ ┌─────────────────────────────────────────┐    │
│ │ Primitive Types           │ │ • Value semantics                       │    │
│ │ (Boolean, Integer)        │ │ • Immutable                             │    │
│ │                           │ │ • Derive from PrimitiveType             │    │
│ └───────────────────────────┘ └─────────────────────────────────────────┘    │
│                                                                              │
│ ┌───────────────────────────┐ ┌─────────────────────────────────────────┐    │
│ │ Byte Sequence Types       │ │ • Ordered byte collections              │    │
│ │ (ByteString, Buffer)      │ │ • ByteString: immutable                 │    │
│ │                           │ │ • Buffer: mutable                       │    │
│ └───────────────────────────┘ └─────────────────────────────────────────┘    │
│                                                                              │
│ ┌───────────────────────────┐ ┌─────────────────────────────────────────┐    │
│ │ Compound Types            │ │ • Reference semantics                   │    │
│ │ (Array, Struct, Map)      │ │ • Contain other items                   │    │
│ │                           │ │ • Derive from CompoundType              │    │
│ │                           │ │ • Struct: clones on copy                │    │
│ └───────────────────────────┘ └─────────────────────────────────────────┘    │
│                                                                              │
│ ┌───────────────────────────┐ ┌─────────────────────────────────────────┐    │
│ │ Special Types             │ │ • Pointer: VM instruction pointer       │    │
│ │ (Pointer, Interop)        │ │ • Interop: interface for host system    │    │
│ │                           │ │   interaction                           │    │
│ └───────────────────────────┘ └─────────────────────────────────────────┘    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Figure 3.2: Neo VM Type Hierarchy

In this hierarchical model:

  1. StackItem Interface: All types implement this common interface, providing the foundation for type operations.

  2. Type Categories:

    • Primitives: Simple value types with immutable values
    • Sequences: Ordered collections of bytes
    • Collections: Container types holding references to other stack items
    • Special Types: VM-internal types and external interface types
  3. Specific Types:

    • Boolean (0x20): Represents boolean values (true/false)
    • Integer (0x21): Represents arbitrary-precision integers
    • ByteString (0x28): Immutable byte sequence
    • Buffer (0x30): Mutable byte sequence
    • Array (0x40): Ordered collection with reference semantics
    • Struct (0x41): Collection with value semantics (deep copy)
    • Map (0x48): Key-value collection with hash-based lookup
    • Pointer (0x10): VM-internal instruction pointer
    • InteropInterface (0x60): Interface to external services

3.2.2 Type Code Allocation

The type codes are allocated in specific ranges:

  • 0x00: Special types
  • 0x10-0x1F: VM control types
  • 0x20-0x2F: Primitive value types
  • 0x28-0x3F: Sequence types
  • 0x40-0x5F: Collection types
  • 0x60-0x7F: External interface types

Type codes not explicitly defined in this specification are reserved for future use.

3.3 Stack Item Interface

All data types MUST implement a common interface with the following operations:

3.3.1 Required Operations

  1. GetType(): MUST return the type code of the item.

  2. GetBoolean(): MUST convert the item to a boolean value according to the conversion rules.

  3. GetInteger(): MUST convert the item to an integer value according to the conversion rules.

  4. GetByteString(): MUST convert the item to a byte string according to the conversion rules.

  5. GetBuffer(): MUST convert the item to a buffer according to the conversion rules or throw an exception if the conversion is not possible.

  6. GetArray(): MUST return the item as an array or throw an exception if the item is not an array or struct.

  7. GetMap(): MUST return the item as a map or throw an exception if the item is not a map.

  8. GetInterface(): MUST return the item as an interface reference or throw an exception if the item is not an interface.

  9. Equals(StackItem): MUST compare two items for equality according to the equality rules.

  10. DeepCopy(uint maxDepth): MUST create a deep copy of the item up to the specified maximum depth.

3.3.2 Stack Item Interface Visualization

┌─────────────────────────────────────────────────────────┐
│                 STACK ITEM INTERFACE                    │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────────────────────────────────────────┐    │
│  │               StackItem Interface               │    │
│  │                                                 │    │
│  │  ┌──────────────────┐  ┌─────────────────────┐  │    │
│  │  │ Type Operations  │  │ Conversion Methods  │  │    │
│  │  ├──────────────────┤  ├─────────────────────┤  │    │
│  │  │ GetType()        │  │ GetBoolean()        │  │    │
│  │  └──────────────────┘  │ GetInteger()        │  │    │
│  │                        │ GetByteString()     │  │    │
│  │  ┌──────────────────┐  │ GetBuffer()         │  │    │
│  │  │ Equality         │  │ GetArray()          │  │    │
│  │  ├──────────────────┤  │ GetMap()            │  │    │
│  │  │ Equals(other)    │  │ GetInterface()      │  │    │
│  │  └──────────────────┘  └─────────────────────┘  │    │
│  │                                                 │    │
│  │  ┌──────────────────┐  ┌─────────────────────┐  │    │
│  │  │ Cloning          │  │ Reference Counting  │  │    │
│  │  ├──────────────────┤  ├─────────────────────┤  │    │
│  │  │ DeepCopy(depth)  │  │ AddStackReference() │  │    │
│  │  └──────────────────┘  │ AddFieldReference() │  │    │
│  │                        │ RemoveStackReference│  │    │
│  │                        │ RemoveFieldReference│  │    │
│  │                        └─────────────────────┘  │    │
│  └─────────────────────────────────────────────────┘    │
│                                                         │
└─────────────────────────────────────────────────────────┘

Figure 3.3: Stack Item Interface Components

3.4 Type Conversion Rules

A conforming implementation MUST apply the following rules when converting between types.

3.4.1 Type Conversion Visual Reference

The following diagram visualizes the permitted type conversions between Neo VM types:

┌────────────────────────────────────────────────────────────┐
│              TYPE CONVERSION RELATIONSHIPS                 │
├────────────────────────────────────────────────────────────┤
│                                                            │
│          ┌─────────┐                                       │
│          │         │                                       │
│  ┌──────►│   Any   │◄──────┐                               │
│  │       │         │       │                               │
│  │       └─────────┘       │                               │
│  │            ▲            │                               │
│  │            │            │                               │
│  │            │            │                               │
│  │       ┌────┴────┐       │                               │
│  │       │         │       │                               │
│  │ ┌────►│ Boolean │◄────┐ │                               │
│  │ │     │         │     │ │                               │
│  │ │     └────┬────┘     │ │                               │
│  │ │          ▲          │ │                               │
│  │ │          │          │ │       ┌───────────────┐       │
│  │ │     ┌────┴────┐     │ │       │               │       │
│  │ │     │         │     │ │       │  Containers   │       │
│  │ │     │ Integer │◄────┼─┼───────┤ (Array/Struct/│       │
│  │ │     │         │     │ │       │     Map)      │       │
│  │ │     └────┬────┘     │ │       │               │       │
│  │ │          ▲          │ │       └───────────────┘       │
│  │ │          │          │ │                               │
│  │ │  ┌───────┴──────┐   │ │       ┌───────────────┐       │
│  │ │  │              │   │ │       │               │       │
│  │ └──┤  ByteString  │◄──┘ │       │    Pointer    │       │
│  │    │              │     │       │               │       │
│  │    └───────┬──────┘     │       └───────────────┘       │
│  │            ▲            │                               │
│  │            │            │       ┌───────────────┐       │
│  │    ┌───────┴──────┐     │       │               │       │
│  └────┤    Buffer    │     │       │ Interop       │       │
│       │              │     │       │ Interface     │       │
│       └──────────────┘     │       │               │       │
│                            │       └───────────────┘       │
│                            │                               │
└────────────────────────────┴───────────────────────────────┘

Figure 3.4: Type Conversion Relationships Diagram

3.4.2 Type Conversion Examples

The following table provides concrete examples of type conversions:

From Type To Type Example Value Converted Value Notes
Boolean Integer true 1 True converts to 1
Boolean Integer false 0 False converts to 0
Boolean ByteString true 0x01 Single byte representation
Boolean ByteString false 0x00 Single byte representation
Integer Boolean 0 false Zero becomes false
Integer Boolean 42 true Any non-zero value becomes true
Integer ByteString 0 (empty) Zero becomes empty string
Integer ByteString 1 0x01 Single byte representation
Integer ByteString 256 0x00 0x01 Little-endian byte order
ByteString Boolean (empty) false Empty string is false
ByteString Boolean 0x00 false Zero bytes are false
ByteString Boolean 0x01 true Any non-zero string is true
ByteString Integer 0x01 1 Interpreted as little-endian
ByteString Integer 0x00 0x01 256 Interpreted as little-endian
Buffer ByteString [0x01, 0x02] 0x01 0x02 Immutable copy is created
Array/Struct/Map Boolean [] false Empty collections are false
Array/Struct/Map Boolean [1,2,3] true Non-empty collections are true
InteropInterface Boolean null false Null interface is false
InteropInterface Boolean (valid ref) true Non-null interface is true

4. Execution Model

4.1 Formal Execution Semantics

GitHub Compatibility Note: The execution model uses formal notation with Unicode symbols (σ, μ, ι) and special characters (⊢, ⟨, ⟩, ⟹) that may not render correctly in all GitHub contexts. When sharing in comments, consider using ASCII alternatives.

4.1.1 Transition Rules

Where:

  • Premises are conditions that must be satisfied for the rule to apply
  • Transition Judgment is a statement of the form ⟨σ, μ, ι, S⟩ ⟹ ⟨σ', μ', ι', S'⟩ indicating a transition from state ⟨σ, μ, ι, S⟩ to state ⟨σ', μ', ι', S'⟩
  • Rule-Name is a label identifying the specific rule

4.1.2 VM State Definition

The state of the VM is formally represented as a tuple ⟨σ, μ, ι, S⟩ where:

  • σ (sigma) represents the VM execution state (NONE, HALT, FAULT)
  • μ (mu) represents the memory state including all allocated objects
  • ι (iota) represents the current instruction being executed
  • S represents the current evaluation stack

Additionally, the complete VM state includes:

  • E represents the execution context, including the invocation stack, instruction pointer, and local variables

The full VM state transition is denoted as:

E ⊢ ⟨σ, μ, ι, S⟩ ⟹ ⟨σ', μ', ι', S'⟩

Where E ⊢ establishes the execution context for the transition.

4.2 Formal Execution Model

A conforming implementation MUST implement the execution model as defined by the following formal transition systems:

4.2.1 Script Loading

  1. When loading a script, the implementation MUST:

    • Validate the script bytecode for structural integrity
    • Create a new Script object containing the bytecode
    • Apply any required initialization to prepare the script for execution
  2. For initialization, the implementation MUST:

    • Create a new ExecutionContext associated with the script
    • Initialize a new evaluation stack for the context
    • Set the instruction pointer to the beginning of the script (position 0)
    • Allocate any required slots (static fields, local variables, arguments) as specified by the script
  3. Before execution begins, the implementation MUST:

    • Push the created context onto the invocation stack
    • Set the VM state to NONE

4.2.2 Execution Lifecycle

The execution lifecycle MUST proceed as follows:

  1. Initialization Phase:

    • Set the current context to the context at the top of the invocation stack
    • Prepare the execution environment
  2. Execution Phase:

    • While the VM state is NONE:
      • Execute the current instruction
      • If an uncaught exception occurs, set the state to FAULT
      • If execution completes successfully, set the state to HALT
  3. Termination Phase:

    • If the state is HALT, collect results from the evaluation stack onto the result stack
    • If the state is FAULT, handle the error condition according to the host environment requirements
    • Release any resources associated with the execution

4.2.3 Bytecode Execution Model

The following diagram illustrates the bytecode execution model of the Neo VM:

┌───────────────────────────────────────────────────────────────────────┐
│                    NEO VM BYTECODE EXECUTION MODEL                    │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│                      ┌─────────────────────────┐                      │
│                      │     SCRIPT BYTECODE     │                      │
│                      └────────────┬────────────┘                      │
│                                   │                                   │
│                                   ▼                                   │
│                ┌─────────────────────────────────────┐                │
│                │          EXECUTION ENGINE           │                │
│                └─────────────────────────────────────┘                │
│                                                                       │
│   ┌──────────────────────────────┐     ┌──────────────────────────┐   │
│   │     INSTRUCTION FETCHER      │     │   INSTRUCTION POINTER    │   │
│   │                              │     │                          │   │
│   │ Reads the next instruction   │◄────┤ Points to current        │   │
│   │ from bytecode at current IP  │     │ position in bytecode     │   │
│   └──────────────┬───────────────┘     └──────────────────────────┘   │
│                  │                                  ▲                 │
│                  ▼                                  │                 │
│  ┌──────────────────────────────┐                   │                 │
│  │       OPCODE DECODER         │                   │                 │
│  │                              │                   │                 │
│  │ Decodes the instruction      │                   │                 │
│  │ and determines handler       │                   │                 │
│  └──────────────┬───────────────┘                   │                 │
│                 │                                   │                 │
│                 ▼                                   │                 │
│  ┌──────────────────────────────┐                   │                 │
│  │       INSTRUCTION            │                   │                 │
│  │       EXECUTION              │───────────────────┘                 │
│  │                              │  Updates IP unless                  │
│  │ Executes the instruction     │  explicitly modified                │
│  │ through appropriate handler  │  by instruction                     │
│  └──────────────┬───────────────┘                                     │
│                 │                                                     │
│                 ▼                                                     │
│  ┌─────────────────────────────────────────────────────────────┐      │
│  │                    INSTRUCTION HANDLERS                     │      │
│  ├─────────────┬─────────────┬─────────────┬───────────────────┤      │
│  │  STACK OPS  │  FLOW CTRL  │ ARITHMETIC  │    OTHER OPS      │      │
│  │             │             │             │                   │      │
│  │ PUSH, POP,  │ CALL, JMP,  │ ADD, SUB,   │ ARRAY, MAP,       │      │
│  │ SWAP, etc.  │ RET, etc.   │ MUL, etc.   │ CONVERT, etc.     │      │
│  └─────────────┴──────┬──────┴─────────────┴───────────────────┘      │
│                       │                                               │
│                       ▼                                               │
│  ┌──────────────────────────────┐     ┌──────────────────────────┐    │
│  │        STATE MACHINE         │     │      VM STATE FLAGS      │    │
│  │                              │     │                          │    │
│  │ Controls VM execution state  │────►│ NONE, HALT, FAULT, BREAK │    │
│  │ based on execution results   │     │                          │    │
│  └──────────────────────────────┘     └──────────────────────────┘    │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

The diagram illustrates the complete bytecode execution flow in the Neo VM:

  1. Script Bytecode: The compiled script containing Neo VM instructions.

  2. Instruction Fetcher and Pointer:

    • The instruction pointer (IP) tracks the current position in the bytecode.
    • The instruction fetcher reads the next instruction from the bytecode at the position indicated by the IP.
  3. Opcode Decoder:

    • Decodes the instruction opcode and any operands.
    • Determines which execution handler should process the instruction.
  4. Instruction Execution:

    • Executes the instruction according to its type (stack operations, flow control, arithmetic, etc.).
    • Manipulates the evaluation stack, alters control flow, performs calculations, or interacts with other VM components.
  5. IP Update:

    • Updates the instruction pointer to the next instruction (unless explicitly modified by a jump or call instruction).
  6. State Machine:

    • Tracks the VM execution state (NONE, HALT, FAULT).
    • Transitions between states based on execution outcomes (successful completion or errors).

The execution process continues until the VM reaches either a HALT state (successful completion) or a FAULT state (execution error).

4.2.3.1 Stack-Based Execution Flow

The Neo VM uses a stack-based execution model where operations consume inputs from and push results to the evaluation stack. The following diagram illustrates this flow:

┌──────────────────────────────────────────────────────────────────────────────┐
│                       STACK-BASED EXECUTION FLOW                             │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────┐        │
│   │                   INSTRUCTION EXECUTION CYCLE                   │        │
│   └─────────────────────────────────────────────────────────────────┘        │
│                                                                              │
│     ┌───────────┐    ┌───────────┐    ┌────────────┐    ┌───────────┐        │
│     │           │    │           │    │            │    │           │        │
│     │  Fetch    │───►│ Decode    │───►│  Execute   │───►│  Advance  │───┐    │
│     │Instruction│    │Instruction│    │Instruction │    │    IP     │   │    │
│     │           │    │           │    │            │    │           │   │    │
│     └───────────┘    └───────────┘    └────────────┘    └───────────┘   │    │
│           ▲                                                             │    │
│           └─────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────┐        │
│   │                         EXECUTE PHASE                           │        │
│   └─────────────────────────────────────────────────────────────────┘        │
│                                                                              │
│     ┌────────────────┐   ┌────────────────┐   ┌────────────────┐             │
│     │                │   │                │   │                │             │
│     │  Fetch Operands│   │Apply Operation │   │ Push Results   │             │
│     │  from Stack    │──►│   to Values    │──►│   to Stack     │             │
│     │                │   │                │   │                │             │
│     └────────────────┘   └────────────────┘   └────────────────┘             │
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────┐        │
│   │                   STACK TRANSITION EXAMPLE                      │        │
│   └─────────────────────────────────────────────────────────────────┘        │
│                                                                              │
│                                                                              │
│  ADD instruction execution:                                                  │
│                                                                              │
│   ┌───────────┐      ┌───────────┐      ┌───────────┐      ┌───────────┐     │
│   │    10     │      │           │      │           │      │    30     │     │
│   ├───────────┤      │           │  ──► │           │  ──► ├───────────┤     │
│   │    20     │  ──► │  10 + 20  │      │    30     │      │    40     │     │
│   ├───────────┤      │           │      │           │      ├───────────┤     │
│   │    40     │      ├───────────┤      ├───────────┤      │    40     │     │
│   └───────────┘      │    40     │      │    40     │      └───────────┘     │
│                      └───────────┘      └───────────┘                        │
│   Instruction        Pop Operands       Compute Result     Push Result       │
│   Fetched                                                                    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

This diagram illustrates the complete execution cycle in Neo VM:

  1. Fetch: The current instruction is retrieved from the script
  2. Decode: The operation and any immediate operands are decoded
  3. Execute: The operation is performed, manipulating the stack
  4. Advance: The instruction pointer is advanced to the next instruction

The execute phase consists of three sub-steps:

  1. Fetch Operands: Pop required operands from the stack
  2. Apply Operation: Perform the operation on the values
  3. Push Results: Push the operation results back onto the stack

The example shows an ADD instruction execution that:

  1. Pops the top two values (10, 20) from the stack
  2. Adds them together to produce 30
  3. Pushes the result (30) back onto the stack

This stack-based execution model ensures deterministic behavior across all Neo VM implementations because each instruction has a well-defined effect on the evaluation stack.

4.2.3.2 Common Stack Operations

The following diagrams illustrate common stack operations in the Neo VM:

┌──────────────────────────────────────────────────────────────────────────────┐
│                          STACK OPERATIONS                                    │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │         PUSH           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before:       After:                 │      │
│  │ Pushes a value onto    │    │ ┌─────┐       ┌─────┐                │      │
│  │ the evaluation stack   │    │ │  B  │       │  X  │  ← New item    │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  B  │                │      │
│  │                        │    │ └─────┘       ├─────┤                │      │
│  │                        │    │               │  A  │                │      │
│  │                        │    │               └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │          POP           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before:       After:                 │      │
│  │ Removes the top item   │    │ ┌─────┐       ┌─────┐                │      │
│  │ from evaluation stack  │    │ │  C  │       │  B  │                │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  B  │       │  A  │                │      │
│  │                        │    │ ├─────┤       └─────┘                │      │
│  │                        │    │ │  A  │                              │      │
│  │                        │    │ └─────┘                              │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │          DUP           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before:       After:                 │      │
│  │ Duplicates the top     │    │ ┌─────┐       ┌─────┐                │      │
│  │ item on the stack      │    │ │  B  │       │  B  │  ← Duplicated  │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  B  │                │      │
│  │                        │    │ └─────┘       ├─────┤                │      │
│  │                        │    │               │  A  │                │      │
│  │                        │    │               └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │         SWAP           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before:       After:                 │      │
│  │ Swaps the top two      │    │ ┌─────┐       ┌─────┐                │      │
│  │ items on the stack     │    │ │  B  │       │  A  │  ← Swapped     │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  B  │  ← Swapped     │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  X  │       │  X  │                │      │
│  │                        │    │ └─────┘       └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │         PICK           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before (n=2):  After:                │      │
│  │ Copies the nth item    │    │ ┌─────┐       ┌─────┐                │      │
│  │ (0-based) to the top   │    │ │  C  │       │  A  │  ← Copied      │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  B  │       │  C  │                │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  B  │                │      │
│  │                        │    │ └─────┘       ├─────┤                │      │
│  │                        │    │               │  A  │                │      │
│  │                        │    │               └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │          ROT           │    │              Effects                 │      │
│  ├────────────────────────┤    ├──────────────────────────────────────┤      │
│  │                        │    │ Before:       After:                 │      │
│  │ Rotates the top three  │    │ ┌─────┐       ┌─────┐                │      │
│  │ items on the stack     │    │ │  C  │       │  A  │                │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  B  │       │  C  │                │      │
│  │                        │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  B  │                │      │
│  │                        │    │ └─────┘       └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

4.2.3.3 Operation Instruction Stack Effects

The following diagrams illustrate how different types of instructions affect the stack:

┌──────────────────────────────────────────────────────────────────────────────┐
│                    OPERATION INSTRUCTION STACK EFFECTS                       │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │        Binary Op       │    │              Effects                 │      │
│  │  (ADD, SUB, MUL, DIV)  │    ├──────────────────────────────────────┤      │
│  ├────────────────────────┤    │ Before:       After:                 │      │
│  │                        │    │ ┌─────┐       ┌─────┐                │      │
│  │ Performs operation on  │    │ │  B  │       │A⊕B │  ← Result       │      │
│  │ the top two values     │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  A  │       │  X  │                │      │
│  │                        │    │ ├─────┤       └─────┘                │      │
│  │                        │    │ │  X  │                              │      │
│  │                        │    │ └─────┘                              │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │       Unary Op         │    │              Effects                 │      │
│  │    (NEG, INC, DEC)     │    ├──────────────────────────────────────┤      │
│  ├────────────────────────┤    │ Before:       After:                 │      │
│  │                        │    │ ┌─────┐       ┌─────┐                │      │
│  │ Performs operation on  │    │ │  A  │       │ ⊕A  │  ← Result      │      │
│  │ the top value          │    │ ├─────┤       ├─────┤                │      │
│  │                        │    │ │  X  │       │  X  │                │      │
│  │                        │    │ └─────┘       └─────┘                │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
│  ┌────────────────────────┐    ┌──────────────────────────────────────┐      │
│  │     Comparison Op      │    │              Effects                 │      │
│  │  (EQ, LT, GT, LTE, GTE)│    ├──────────────────────────────────────┤      │
│  ├────────────────────────┤    │ Before:       After:                 │      │
│  │                        │    │ ┌─────┐       ┌─────────┐            │      │
│  │ Compares the top two   │    │ │  B  │       │Boolean  │  ← Result  │      │
│  │ values, pushes boolean │    │ ├─────┤       │(A comp B)│           │      │
│  │                        │    │ │  A  │       ├─────────┤            │      │
│  │                        │    │ ├─────┤       │    X    │            │      │
│  │                        │    │ │  X  │       └─────────┘            │      │
│  │                        │    │ └─────┘                              │      │
│  └────────────────────────┘    └──────────────────────────────────────┘      │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

These visualizations provide a clear understanding of how stack operations work in the Neo VM, which is essential for implementers to correctly handle the evaluation stack during execution.

5. Instruction Set

5.1 Instruction Categories

5.1.1 Constants (0x00-0x20)

Constants instructions allow for pushing constant values onto the stack.

Opcode Mnemonic Description Stack Effect
0x00 PUSHINT8 Pushes a 1-byte signed integer onto the stack +1
0x01 PUSHINT16 Pushes a 2-byte signed integer onto the stack +1
0x02 PUSHINT32 Pushes a 4-byte signed integer onto the stack +1
0x03 PUSHINT64 Pushes an 8-byte signed integer onto the stack +1
0x04 PUSHINT128 Pushes a 16-byte signed integer onto the stack +1
0x05 PUSHINT256 Pushes a 32-byte signed integer onto the stack +1
0x08 PUSHT Pushes the boolean value true onto the stack +1
0x09 PUSHF Pushes the boolean value false onto the stack +1
0x0A PUSHA Converts a 4-byte offset to a Pointer and pushes it onto the stack +1
0x0B PUSHNULL Pushes null onto the stack +1
0x0C PUSHDATA1 Pushes bytes onto the stack (1-byte length prefix) +1
0x0D PUSHDATA2 Pushes bytes onto the stack (2-byte length prefix) +1
0x0E PUSHDATA4 Pushes bytes onto the stack (4-byte length prefix) +1
0x0F PUSHM1 Pushes the integer -1 onto the stack +1
0x10 PUSH0 Pushes the integer 0 onto the stack +1
0x11 PUSH1 Pushes the integer 1 onto the stack +1
0x12 PUSH2 Pushes the integer 2 onto the stack +1
0x13 PUSH3 Pushes the integer 3 onto the stack +1
0x14 PUSH4 Pushes the integer 4 onto the stack +1
0x15 PUSH5 Pushes the integer 5 onto the stack +1
0x16 PUSH6 Pushes the integer 6 onto the stack +1
0x17 PUSH7 Pushes the integer 7 onto the stack +1
0x18 PUSH8 Pushes the integer 8 onto the stack +1
0x19 PUSH9 Pushes the integer 9 onto the stack +1
0x1A PUSH10 Pushes the integer 10 onto the stack +1
0x1B PUSH11 Pushes the integer 11 onto the stack +1
0x1C PUSH12 Pushes the integer 12 onto the stack +1
0x1D PUSH13 Pushes the integer 13 onto the stack +1
0x1E PUSH14 Pushes the integer 14 onto the stack +1
0x1F PUSH15 Pushes the integer 15 onto the stack +1
0x20 PUSH16 Pushes the integer 16 onto the stack +1

5.1.2 Flow Control (0x21-0x41)

Flow control instructions allow for controlling the execution flow of the VM.

Opcode Mnemonic Description Stack Effect
0x21 NOP No operation 0
0x22 JMP Jump to a target instruction (1-byte offset) 0
0x23 JMP_L Jump to a target instruction (4-byte offset) 0
0x24 JMPIF Jump if the value is true (1-byte offset) -1
0x25 JMPIF_L Jump if the value is true (4-byte offset) -1
0x26 JMPIFNOT Jump if the value is false (1-byte offset) -1
0x27 JMPIFNOT_L Jump if the value is false (4-byte offset) -1
0x28 JMPEQ Jump if two values are equal (1-byte offset) -2
0x29 JMPEQ_L Jump if two values are equal (4-byte offset) -2
0x2A JMPNE Jump if two values are not equal (1-byte offset) -2
0x2B JMPNE_L Jump if two values are not equal (4-byte offset) -2
0x2C JMPGT Jump if first value is greater than second value (1-byte offset) -2
0x2D JMPGT_L Jump if first value is greater than second value (4-byte offset) -2
0x2E JMPGE Jump if first value is greater than or equal to second value (1-byte offset) -2
0x2F JMPGE_L Jump if first value is greater than or equal to second value (4-byte offset) -2
0x30 JMPLT Jump if first value is less than second value (1-byte offset) -2
0x31 JMPLT_L Jump if first value is less than second value (4-byte offset) -2
0x32 JMPLE Jump if first value is less than or equal to second value (1-byte offset) -2
0x33 JMPLE_L Jump if first value is less than or equal to second value (4-byte offset) -2
0x34 CALL Call a function at target address (1-byte offset) Varies
0x35 CALL_L Call a function at target address (4-byte offset) Varies
0x36 CALLA Call a function using address from stack Varies
0x37 CALLT Call a function using token Varies
0x38 ABORT Abort execution 0
0x39 ASSERT Assert that condition is true -1
0x3A THROW Throw an exception -1
0x3B TRY Start a try-catch-finally block (1-byte offsets) 0
0x3C TRY_L Start a try-catch-finally block (4-byte offsets) 0
0x3D ENDTRY End a try block (1-byte offset) 0
0x3E ENDTRY_L End a try block (4-byte offset) 0
0x3F ENDFINALLY End a finally block 0
0x40 RET Return from function Varies
0x41 SYSCALL Call a system function Varies

5.1.3 Stack Operations (0x43-0x55)

Stack operations instructions allow for manipulating the elements on the stack.

Opcode Mnemonic Description Stack Effect
0x43 DEPTH Puts the number of stack items onto the stack +1
0x45 DROP Removes the top stack item -1
0x46 NIP Removes the second-to-top stack item -1
0x48 XDROP Removes the item n back in the stack -(n+1)
0x49 CLEAR Clears the stack -all
0x4A DUP Duplicates the top stack item +1
0x4B OVER Copies the second-to-top stack item to the top +1
0x4D PICK Copies the item n back in the stack to the top +1
0x4E TUCK Copies the top item before the second-to-top item +1
0x50 SWAP Swaps the top two items on the stack 0
0x51 ROT Rotates the top three items on the stack 0
0x52 ROLL Moves the item n back in the stack to the top 0
0x53 REVERSE3 Reverses the order of the top 3 items on the stack 0
0x54 REVERSE4 Reverses the order of the top 4 items on the stack 0
0x55 REVERSEN Reverses the order of the top n items on the stack -1

5.1.4 Slot Operations (0x56-0x87)

Slot operations instructions allow for accessing and manipulating local variables, arguments, and static fields.

Opcode Mnemonic Description Stack Effect
0x56 INITSSLOT Initialize the static field list 0
0x57 INITSLOT Initialize the local variable and argument slots 0
0x58 LDSFLD0 Load static field 0 onto the stack +1
0x59 LDSFLD1 Load static field 1 onto the stack +1
0x5A LDSFLD2 Load static field 2 onto the stack +1
0x5B LDSFLD3 Load static field 3 onto the stack +1
0x5C LDSFLD4 Load static field 4 onto the stack +1
0x5D LDSFLD5 Load static field 5 onto the stack +1
0x5E LDSFLD6 Load static field 6 onto the stack +1
0x5F LDSFLD Load static field at specified index onto the stack +1
0x60 STSFLD0 Store top stack item to static field 0 -1
0x61 STSFLD1 Store top stack item to static field 1 -1
0x62 STSFLD2 Store top stack item to static field 2 -1
0x63 STSFLD3 Store top stack item to static field 3 -1
0x64 STSFLD4 Store top stack item to static field 4 -1
0x65 STSFLD5 Store top stack item to static field 5 -1
0x66 STSFLD6 Store top stack item to static field 6 -1
0x67 STSFLD Store top stack item to static field at specified index -1
0x68 LDLOC0 Load local variable 0 onto the stack +1
0x69 LDLOC1 Load local variable 1 onto the stack +1
0x6A LDLOC2 Load local variable 2 onto the stack +1
0x6B LDLOC3 Load local variable 3 onto the stack +1
0x6C LDLOC4 Load local variable 4 onto the stack +1
0x6D LDLOC5 Load local variable 5 onto the stack +1
0x6E LDLOC6 Load local variable 6 onto the stack +1
0x6F LDLOC Load local variable at specified index onto the stack +1
0x70 STLOC0 Store to local variable 0 -1
0x71 STLOC1 Store to local variable 1 -1
0x72 STLOC2 Store to local variable 2 -1
0x73 STLOC3 Store to local variable 3 -1
0x74 STLOC4 Store to local variable 4 -1
0x75 STLOC5 Store to local variable 5 -1
0x76 STLOC6 Store to local variable 6 -1
0x77 STLOC Store to local variable at specified index -1
0x78 LDARG0 Load argument 0 onto the stack +1
0x79 LDARG1 Load argument 1 onto the stack +1
0x7A LDARG2 Load argument 2 onto the stack +1
0x7B LDARG3 Load argument 3 onto the stack +1
0x7C LDARG4 Load argument 4 onto the stack +1
0x7D LDARG5 Load argument 5 onto the stack +1
0x7E LDARG6 Load argument 6 onto the stack +1
0x7F LDARG Load argument at specified index onto the stack +1
0x80 STARG0 Store to argument 0 -1
0x81 STARG1 Store to argument 1 -1
0x82 STARG2 Store to argument 2 -1
0x83 STARG3 Store to argument 3 -1
0x84 STARG4 Store to argument 4 -1
0x85 STARG5 Store to argument 5 -1
0x86 STARG6 Store to argument 6 -1
0x87 STARG Store to argument at specified index -1
0x88 NEWBUFFER Creates a new buffer with specified size 0
0x89 MEMCPY Copies bytes from one buffer to another -5
0x8B CAT Concatenates two strings or buffers -1
0x8C SUBSTR Returns a section of a string -2
0x8D LEFT Keeps only characters left of specified point in a string -1
0x8E RIGHT Keeps only characters right of specified point in a string -1
0x90 INVERT Flips all bits in the input 0
0x91 AND Performs bitwise AND operation -1
0x92 OR Performs bitwise OR operation -1
0x93 XOR Performs bitwise XOR operation -1
0x97 EQUAL Returns true if inputs are exactly equal -1
0x98 NOTEQUAL Returns true if inputs are not equal -1
0x99 SIGN Returns the sign of a number (-1, 0, or 1) 0
0x9A ABS Returns the absolute value of a number 0
0x9B NEGATE Negates a number 0
0x9C INC Increments a number by 1 0
0x9D DEC Decrements a number by 1 0
0x9E ADD Adds two numbers -1
0x9F SUB Subtracts one number from another -1
0xA0 MUL Multiplies two numbers -1
0xA1 DIV Divides one number by another -1
0xA2 MOD Returns the remainder after division -1
0xA3 POW Raises a number to a power -1
0xA4 SQRT Returns the square root of a number 0
0xA5 MODMUL Performs modulus division on a number multiplied by another -2
0xA6 MODPOW Performs modular exponentiation -2
0xA8 SHL Shifts bits left -1
0xA9 SHR Shifts bits right -1
0xAA NOT Logical NOT (flips boolean values) 0
0xAB BOOLAND Logical AND -1
0xAC BOOLOR Logical OR -1
0xB1 NZ Returns true if input is non-zero 0
0xB3 NUMEQUAL Returns true if numbers are equal -1
0xB4 NUMNOTEQUAL Returns true if numbers are not equal -1
0xB5 LT Returns true if a is less than b -1
0xB6 LE Returns true if a is less than or equal to b -1
0xB7 GT Returns true if a is greater than b -1
0xB8 GE Returns true if a is greater than or equal to b -1
0xB9 MIN Returns the minimum of two values -1
0xBA MAX Returns the maximum of two values -1
0xBB WITHIN Returns true if a value is within a range -2
0xBE PACKMAP Creates a map from key-value pairs on the stack -(2n+1)
0xBF PACKSTRUCT Packs multiple items into a struct -(n+1)
0xC0 PACK Packs multiple items into an array -(n+1)
0xC1 UNPACK Unpacks an array or map into its elements Varies
0xC2 NEWARRAY0 Creates an empty array +1
0xC3 NEWARRAY Creates an array of specified size 0
0xC4 NEWARRAY_T Creates a typed array of specified size 0
0xC5 NEWSTRUCT0 Creates an empty struct +1
0xC6 NEWSTRUCT Creates a struct of specified size 0
0xC8 NEWMAP Creates an empty map +1
0xCA SIZE Returns the size of an array, string, or map 0
0xCB HASKEY Checks if a key exists in a map or index is valid in array -1
0xCC KEYS Gets all keys from a map 0
0xCD VALUES Gets all values from a map 0
0xCE PICKITEM Gets an item from an array, string, map, or struct -1
0xCF APPEND Appends an item to an array -2
0xD0 SETITEM Sets an item in an array, map, or struct -3
0xD1 REVERSEITEMS Reverses the items in an array -1
0xD2 REMOVE Removes an item from an array, map, or dictionary -2
0xD3 CLEARITEMS Clears all items from a compound type -1
0xD4 POPITEM Removes and returns the last item from an array 0
0xD8 ISNULL Check if value is null x → bool
0xD9 ISTYPE Check if value is of specified type x → bool
0xDB CONVERT Convert to specified type x → converted
0xE0 ABORTMSG Abort execution with the top stack item as the error message -1
0xE1 ASSERTMSG Assert condition with custom error message -2

5.2 Constants and Push Operations

The following operations push constant values onto the evaluation stack:

OpCode Hex Operand Size Description Stack [top first]
PUSHINT8 0x00 1 byte Push 8-bit signed integer value onto the stack → value
PUSHINT16 0x01 2 bytes Push 16-bit signed integer value onto the stack → value
PUSHINT32 0x02 4 bytes Push 32-bit signed integer value onto the stack → value
PUSHINT64 0x03 8 bytes Push 64-bit signed integer value onto the stack → value
PUSHINT128 0x04 16 bytes Push 128-bit signed integer value onto the stack → value
PUSHINT256 0x05 32 bytes Push 256-bit signed integer value onto the stack → value
PUSHA 0x0A 4 bytes Push 4-byte instruction pointer onto the stack → address
PUSHNULL 0x0B 0 bytes Push null reference onto the stack → null
PUSHDATA1 0x0C 1+n bytes Push data with 1-byte length specifier → data
PUSHDATA2 0x0D 2+n bytes Push data with 2-byte length specifier → data
PUSHDATA4 0x0E 4+n bytes Push data with 4-byte length specifier → data
PUSHM1-PUSH16 0x11-0x21 0 bytes Push small integer constants (-1 to 16) → value
PUSHT/PUSHF 0x22/0x23 0 bytes Push boolean True/False onto the stack → True/False

5.2.1 PUSHDATA Encoding

PUSHDATA instructions MUST use the following encoding:

  1. PUSHDATA1: 0x0C <1-byte length> <data bytes>
  2. PUSHDATA2: 0x0D <2-byte length> <data bytes>
  3. PUSHDATA4: 0x0E <4-byte length> <data bytes>

Where the length field specifies the number of data bytes that follow.

5.3 Flow Control Operations

Flow control operations modify the instruction pointer and control execution flow:

OpCode Hex Operand Size Description Stack [top first]
JMP 0x40 2 bytes Jump to offset
JMP_L 0x41 4 bytes Unconditional jump with 4-byte offset
JMPIF 0x42 2 bytes Jump if top item is true, 1-byte offset cond → ø
JMPIF_L 0x43 8 bytes Jump if top item is true, 4-byte offset cond → ø
JMPIFNOT 0x44 2 bytes Jump if top item is false, 1-byte offset cond → ø
JMPIFNOT_L 0x45 8 bytes Jump if top item is false, 4-byte offset cond → ø
CALL 0x46 2 bytes Call target with 1-byte offset
CALL_L 0x47 4 bytes Call target with 4-byte offset
CALLA 0x48 0 bytes Call target using address from stack address → ø
RET 0x49 0 bytes Return from current context
SYSCALL 0x4A 4 bytes Call interop service by ID args... → result
TRY 0x4B 2 bytes Begin try block, with 1-byte offsets to catch and finally
TRY_L 0x4C 8 bytes Begin try block, with 4-byte offsets to catch and finally
ENDTRY 0x4D 1 byte End try block, with 1-byte offset to handler end
ENDTRY_L 0x4E 4 bytes End try block, with 4-byte offset to handler end
ENDFINALLY 0x4F 0 bytes End finally block
THROW 0x50 0 bytes Throw top item as exception exception → ø

5.3.1 Jump Offset Calculation

For jump operations, the offset is calculated as follows:

  1. The offset is a signed integer (1-byte or 4-bytes).
  2. The offset is relative to the instruction pointer after the jump instruction and its operand.
  3. A positive offset jumps forward, a negative offset jumps backward.

5.3.2 TRY-CATCH-FINALLY Structure

The TRY/TRY_L instruction contains two offset operands:

  1. The first offset points to the start of the CATCH block
  2. The second offset points to the start of the FINALLY block (or end of TRY if no FINALLY)

ENDTRY/ENDTRY_L marks the end of a CATCH block with an offset to the end of the entire structure (after FINALLY if present).

5.3.3 Exception Handling Flow Visualization

The following diagram illustrates the control flow during exception handling:

┌─────────────────────────────────────────────────────────────────────────┐
│                       EXCEPTION HANDLING FLOW                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│                           ┌──────────────┐                              │
│    ┌───────────────────┐  │ Entry Point  │  ┌────────────────────┐     │
│    │ Program Flow      │◄─┤              ├─►│                    │     │
│    └─────────┬─────────┘  └──────────────┘  │  Exception Thrown  │     │
│              │                               │  Outside TRY      │     │
│              │                               └────────────────────┘     │
│              ▼                                         │                │
│    ┌─────────────────────┐                             │                │
│    │                     │                             │                │
│    │      TRY Block      │                             │                │
│    │                     │                             │                │
│    └─────────┬─────────┬─┘                             │                │
│              │         │                               │                │
│     No Exception       │ Exception Thrown              │                │
│              │         │                               │                │
│              │         ▼                               │                │
│              │   ┌───────────────┐                     │                │
│              │   │ Find Matching │                     │                │
│              │   │ CATCH Block   │                     │                │
│              │   └───────┬───────┘                     │                │
│              │           │                             │                │
│              │     Found │       │ Not Found           │                │
│              │           │       │                     │                │
│              │           ▼       ▼                     ▼                │
│              │   ┌─────────────────────┐      ┌────────────────┐       │
│              │   │                     │      │                │       │
│              │   │    CATCH Block      │      │   FAULT State  │       │
│              │   │                     │      │                │       │
│              │   └─────────┬───────────┘      └────────────────┘       │
│              │             │                                            │
│              │             │                                            │
│              │             │ ENDTRY                                     │
│              │             │                                            │
│              ▼             ▼                                            │
│    ┌────────────────────────┐                                           │
│    │                        │                                           │
│    │     FINALLY Block      │                                           │
│    │    (if present)        │                                           │
│    │                        │                                           │
│    └───────────┬────────────┘                                           │
│                │                                                        │
│                │ ENDFINALLY                                             │
│                │                                                        │
│                ▼                                                        │
│    ┌────────────────────────┐                                           │
│    │                        │                                           │
│    │  Continue Normal Flow  │                                           │
│    │                        │                                           │
│    └────────────────────────┘                                           │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

The diagram illustrates the complete exception handling process in Neo VM:

  1. Execution begins in the TRY block after normal program flow.
  2. If no exception occurs, control flows directly to the FINALLY block (if present).
  3. If an exception occurs in the TRY block, the VM searches for a matching CATCH handler.
  4. If a matching CATCH handler is found, execution continues in the CATCH block.
  5. After the CATCH block completes (with ENDTRY), control passes to the FINALLY block.
  6. If no matching CATCH handler is found, the VM enters the FAULT state (unless caught at a higher level).
  7. The FINALLY block always executes regardless of the path taken (normal completion, handled exception, or unhandled exception).
  8. After the FINALLY block completes (with ENDFINALLY), execution continues with normal program flow.
  9. If an exception occurs outside a TRY block (or is re-thrown), the VM enters the FAULT state.

Key points:

  • The FINALLY block is guaranteed to execute in all cases, even if an exception occurs in the TRY or CATCH blocks.
  • ENDTRY is used to mark the end of a CATCH handler, while ENDFINALLY marks the end of a FINALLY block.
  • If another exception occurs during CATCH or FINALLY execution, the VM enters the FAULT state (unless nested in another TRY).

5.3.4 Formal Operational Semantics for Flow Control

The following formal semantics define precisely how flow control operations transform the VM state:

Note: The formal notation below displays best in a monospace font. Special symbols: ⊢ (turnstile), ⟨ ⟩ (angle brackets), ⟹ (double arrow).

// JMP operation (unconditional jump)
                 offset = decode-offset(ι)
---------------------------------------------------------------- [JMP]
E ⊢ ⟨σ, μ, ι = JMP, S⟩ ⟹ ⟨σ, μ, ι + offset, S⟩

// JMPIF operation (conditional jump if true)
        S = [..., c], IsBoolean(c), c = true, offset = decode-offset(ι)
---------------------------------------------------------------- [JMPIF-TRUE]
E ⊢ ⟨σ, μ, ι = JMPIF, S⟩ ⟹ ⟨σ, μ, ι + offset, S' = [...]⟩

// JMPIF operation (conditional jump if false)
        S = [..., c], IsBoolean(c), c = false
---------------------------------------------------------------- [JMPIF-FALSE]
E ⊢ ⟨σ, μ, ι = JMPIF, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [...]⟩

// JMPIFNOT operation (conditional jump if false)
        S = [..., c], IsBoolean(c), c = false, offset = decode-offset(ι)
---------------------------------------------------------------- [JMPIFNOT-FALSE]
E ⊢ ⟨σ, μ, ι = JMPIFNOT, S⟩ ⟹ ⟨σ, μ, ι + offset, S' = [...]⟩

// JMPIFNOT operation (conditional jump if true)
        S = [..., c], IsBoolean(c), c = true
---------------------------------------------------------------- [JMPIFNOT-TRUE]
E ⊢ ⟨σ, μ, ι = JMPIFNOT, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [...]⟩

// CALL operation (function call)
                 offset = decode-offset(ι)
---------------------------------------------------------------- [CALL]
E ⊢ ⟨σ, μ, ι = CALL, S, I⟩ ⟹ ⟨σ, μ, ι' = ι + offset, S, I' = I + [return_address = next(ι)]⟩

// RET operation (function return)
                 I = [..., return_address]
---------------------------------------------------------------- [RET]
E ⊢ ⟨σ, μ, ι = RET, S, I⟩ ⟹ ⟨σ, μ, ι' = return_address, S, I' = [...]⟩

Where:

  • E is the execution environment
  • σ is the current VM state
  • μ is the memory state
  • ι is the instruction being executed
  • S is the current evaluation stack
  • S' is the resulting stack after the operation
  • I is the invocation stack
  • I' is the resulting invocation stack after the operation
  • next(ι) is the next instruction after ι
  • decode-offset(ι) retrieves the jump offset encoded in the instruction
  • isBoolean(c) is a predicate that checks if c is a boolean value

5.3.4 Flow Control State Transition Table

The following table precisely defines the state transition for flow control operations:

Operation Pre-State Post-State Conditions
JMP ip = x ip = x + offset -
JMP_L ip = x ip = x + offset(4-byte) -
JMPIF ip = x, cond, ... ip = x + offset, ... if cond is true
JMPIF ip = x, cond, ... ip = x + size(instr), ... if cond is false
JMPIFNOT ip = x, cond, ... ip = x + offset, ... if cond is false
JMPIFNOT ip = x, cond, ... ip = x + size(instr), ... if cond is true
CALL ip = x, ctx = c ip = x + offset, ctx = new, c.ReturnIP = x + size(instr) New execution context created
RET ip = x, ctx = c ip = c.ReturnIP, ctx = c.parent Context c is unloaded
SYSCALL ip = x, args... ip = x + size(instr), result System call executed

Where:

  • ip is the instruction pointer
  • offset is the jump offset (1-byte for standard, 4-byte for L-variants)
  • ctx is the current execution context
  • c.ReturnIP is the return address stored in the context
  • size(instr) is the size of the current instruction including operands

These formal semantics ensure that flow control operations are implemented consistently across all Neo VM implementations.

5.3 Stack Operations

Stack operations manipulate items on the evaluation stack without performing computation on their values:

OpCode Hex Operand Size Description Stack [top first]
DUP 0x60 0 bytes Duplicate the top item on the stack x → x x
NIP 0x61 0 bytes Remove the second item on the stack x₁ x₂ → x₁
OVER 0x62 0 bytes Copy the second item to the top x₁ x₂ → x₁ x₂ x₁
PICK 0x63 0 bytes Copy the nth item to the top (n=0 for top) xₙ ... x₀ n → xₙ ... x₀ xₙ
SWAP 0x64 0 bytes Swap the top two items x₁ x₂ → x₂ x₁
TUCK 0x65 0 bytes Copy the top item below the second item x₁ x₂ → x₂ x₁ x₂
ROT 0x66 0 bytes Rotate the top three items x₁ x₂ x₃ → x₂ x₃ x₁
DEPTH 0x69 0 bytes Push the number of items onto the stack ... → ... n
DROP 0x6A 0 bytes Remove the top item x → ø
XDROP 0x6B 0 bytes Remove the nth item (n=0 for top) xₙ ... x₀ n → x₀ ... xₙ₋₁
CLEAR 0x6C 0 bytes Remove all items from the stack x₁ x₂ ... → ø
ROLL 0x6E 0 bytes Move the nth item to the top xₙ ... x₀ n → ... x₀ xₙ

5.3.1 Stack Operation Requirements

A conforming implementation MUST ensure the following for stack operations:

  1. Stack Underflow Prevention:

    • Before executing a stack operation, verify that the stack contains enough items for the operation
    • If the stack does not contain enough items, the VM MUST enter the FAULT state
  2. Stack Operation Semantics:

    • DUP MUST create a duplicate reference to the same object (not a deep copy)
    • ROLL and PICK MUST interpret negative indices as relative to the bottom of the stack
    • DEPTH MUST push the current number of items on the stack as an Integer
  3. Reference Counting Consistency:

    • Stack operations MUST properly maintain reference counts for all affected objects
    • When an item is duplicated, its reference count MUST be incremented
    • When an item is removed from the stack, its reference count MUST be decremented

5.3.2 Formal Operational Semantics for Stack Operations

The following formal semantics define precisely how stack operations transform the VM state:

// DUP operation
                    S = [..., v]
---------------------------------------------------------------- [DUP]
E ⊢ ⟨σ, μ, ι = DUP, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., v, v]⟩

// ROLL operation (moves the nth item to the top)
         S = [..., vn, vn-1, ..., v1, v0, n], isInteger(n), n ≥ 0
---------------------------------------------------------------- [ROLL]
E ⊢ ⟨σ, μ, ι = ROLL, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., vn-1, ..., v1, v0, vn]⟩

// DROP operation
                  S = [..., v]
---------------------------------------------------------------- [DROP]
E ⊢ ⟨σ, μ, ι = DROP, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [...]⟩

// DEPTH operation (pushes the number of items onto the stack)
                  S = [v0, v1, ..., vn]
---------------------------------------------------------------- [DEPTH]
E ⊢ ⟨σ, μ, ι = DEPTH, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [v0, v1, ..., vn, n+1]⟩

Where:

  • E is the execution environment
  • σ is the current VM state
  • μ is the memory state
  • ι is the instruction being executed
  • S is the current evaluation stack
  • S' is the resulting stack after the operation
  • next(ι) is the next instruction after ι
  • isInteger(n) is a predicate that checks if n is an integer value

5.3.3 State Transition Table for Stack Operations

The following table precisely defines the state transition for each stack operation:

Operation Pre-State (Stack Top→Bottom) Post-State (Stack Top→Bottom) Conditions
DUP x, ... x, x, ... -
DUPFROMALTSTACK ...(main), x,...(alt) x,...(main), x,...(alt) Alt stack not empty
SWAP x, y, ... y, x, ... At least 2 items on stack
ROLL xn,...,x1,x0,n x0,...,xn-1,xn n ≥ 0, sufficient items
PICK xn,...,x0,n xn,...,x0,xn n ≥ 0, sufficient items
ROT x1, x2, x3, ... x3, x1, x2, ... At least 3 items on stack
DEPTH ... n, ... n = stack.size()
DROP x, ... ... At least 1 item on stack
XDROP xn,...,x0,n xn-1,...,x0 n ≥ 0, sufficient items
CLEAR x1, x2, ... (empty) -

This table and the formal semantics ensure deterministic behavior for all stack operations across all Neo VM implementations.

5.3.4 Stack Operation Visualization

The following diagrams visually illustrate how common stack operations affect the evaluation stack:

┌─────────────────────┐   ┌─────────────────────┐
│     DUP (0x60)      │   │     NIP (0x61)      │
├─────────────────────┤   ├─────────────────────┤
│ Before      After   │   │ Before      After   │
├─────────────────────┤   ├─────────────────────┤
│   ┌───┐      ┌───┐  │   │   ┌───┐      ┌───┐  │
│   │ A │      │ A │  │   │   │ A │      │ A │  │
│   ├───┤      ├───┤  │   │   ├───┤      └───┘  │
│   │...│      │ A │  │   │   │ B │        │    │
│   └───┘      ├───┤  │   │   ├───┤        │    │
│              │...│  │   │   │...│        ▼    │
│              └───┘  │   │   └───┘      ┌───┐  │
│                     │   │              │...│  │
└─────────────────────┘   │              └───┘  │
                          └─────────────────────┘

┌─────────────────────┐   ┌─────────────────────┐
│     SWAP (0x64)     │   │     ROT (0x66)      │
├─────────────────────┤   ├─────────────────────┤
│ Before      After   │   │ Before      After   │
├─────────────────────┤   ├─────────────────────┤
│   ┌───┐      ┌───┐  │   │   ┌───┐      ┌───┐  │
│   │ A │      │ B │  │   │   │ A │      │ B │  │
│   ├───┤      ├───┤  │   │   ├───┤      ├───┤  │
│   │ B │      │ A │  │   │   │ B │      │ C │  │
│   ├───┤      ├───┤  │   │   ├───┤      ├───┤  │
│   │...│      │...│  │   │   │ C │      │ A │  │
│   └───┘      └───┘  │   │   ├───┤      ├───┤  │
│                     │   │   │...│      │...│  │
└─────────────────────┘   │   └───┘      └───┘  │
                          └─────────────────────┘

┌─────────────────────┐   ┌─────────────────────┐
│     PICK (0x63)     │   │     ROLL (0x6E)     │
├─────────────────────┤   ├─────────────────────┤
│ Before      After   │   │ Before      After   │
├─────────────────────┤   ├─────────────────────┤
│   ┌───┐      ┌───┐  │   │   ┌───┐      ┌───┐  │
│   │ 2 │      │ C │  │   │   │ 2 │      │ C │  │
│   ├───┤      ├───┤  │   │   ├───┤      ├───┤  │
│   │ A │      │ A │  │   │   │ A │      │ A │  │
│   ├───┤      ├───┤  │   │   ├───┤      ├───┤  │
│   │ B │      │ B │  │   │   │ B │      │ D │  │
│   ├───┤      ├───┤  │   │   ├───┤      ├───┤  │
│   │ C │      │ C │  │   │   │ C │      │...│  │
│   ├───┤      ├───┤  │   │   ├───┤      └───┘  │
│   │ D │      │ D │  │   │   │ D │             │
│   ├───┤      ├───┤  │   │   ├───┤             │
│   │...│      │...│  │   │   │...│             │
│   └───┘      └───┘  │   │   └───┘             │
└─────────────────────┘   └─────────────────────┘

These visualizations illustrate how stack items are manipulated during key operations. The stack grows downward, with the top of the stack at the top of each diagram. In the PICK example, the value 2 indicates that the item at depth 2 (item C) should be copied to the top. In the ROLL example, the value 2 indicates that the item at depth 2 (item C) should be moved to the top.

5.4 Slot Operations

Slot operations manage local variables, arguments, and static fields:

OpCode Hex Operand Size Description Stack [top first]
INITSLOT 0x6D 2 bytes Initialize local and arg slots (first byte local count, second byte arg count)
LDLOC0-3 0x70-0x73 0 bytes Load local variable 0-3 onto the stack → value
LDLOC 0x74 1 byte Load local variable by index → value
STLOC0-3 0x75-0x78 0 bytes Store top item to local variable 0-3 value → ø
STLOC 0x79 1 byte Store top item to local variable by index value → ø
LDARG0-3 0x7A-0x7D 0 bytes Load argument 0-3 onto the stack → value
LDARG 0x7E 1 byte Load argument by index → value
STARG0-3 0x7F-0x82 0 bytes Store top item to argument 0-3 value → ø
STARG 0x83 1 byte Store top item to argument by index value → ø
LDSFLD0-3 0x84-0x87 0 bytes Load static field 0-3 onto the stack → value
LDSFLD 0x88 1 byte Load static field by index → value
STSFLD0-3 0x89-0x8C 0 bytes Store top item to static field 0-3 value → ø
STSFLD 0x8D 1 byte Store top item to static field by index value → ø

5.4.1 Slot Operation Requirements

A conforming implementation MUST ensure the following for slot operations:

  1. Slot Initialization:

    • INITSLOT MUST be called before any other slot operations in a context
    • INITSLOT MUST allocate the specified number of slots for local variables and arguments
    • INITSLOT MUST be called at most once per execution context
  2. Slot Access Bounds Checking:

    • All slot access operations MUST verify that the slot index is within bounds
    • If a slot index is out of bounds, the VM MUST enter the FAULT state
  3. Reference Counting for Slots:

    • When storing a value to a slot that already contains a value, the old value's reference count MUST be decremented
    • When loading a value from a slot, its reference count MUST be incremented
    • When storing a value to a slot, the stored value's reference count MUST be incremented

5.5 Type Operations

Type operations check and convert between different types:

OpCode Hex Operand Size Description Stack [top first]
ISNULL 0x90 0 bytes Push TRUE if top item is null, FALSE otherwise x → bool
ISTYPE 0x91 1 byte Push TRUE if top item is of specified type x → bool
CONVERT 0x92 1 byte Convert top item to specified type x → value

5.5.1 Type Operation Requirements

A conforming implementation MUST ensure the following for type operations:

  1. Type Codes:

    • Type codes used with ISTYPE and CONVERT MUST match the type codes defined in section 3.3
    • If an invalid type code is specified, the VM MUST enter the FAULT state
  2. Type Conversion Rules:

    • CONVERT MUST follow the type conversion rules defined in section 3.4
    • If a conversion is not possible, the VM MUST enter the FAULT state
  3. Null Handling:

    • ISNULL MUST push TRUE if the top item is null, FALSE otherwise
    • ISTYPE MUST push FALSE if the top item is null, regardless of the specified type

5.6 Splice Operations

Splice operations manipulate buffers and strings:

OpCode Hex Operand Size Description Stack [top first]
NEWBUFFER 0xA0 0 bytes Create a new buffer with size from stack size → buffer
MEMCPY 0xA1 0 bytes Copy data between buffers src₁ index₁ dest₂ index₂ size → ø
CAT 0xA2 0 bytes Concatenate two strings or buffers x₁ x₂ → x₁+x₂
SUBSTR 0xA3 0 bytes Extract substring from string or buffer str index length → substr
LEFT 0xA4 0 bytes Extract leftmost characters from string str count → substr
RIGHT 0xA5 0 bytes Extract rightmost characters from string str count → substr

5.6.1 Splice Operation Requirements

A conforming implementation MUST ensure the following for splice operations:

  1. Buffer Allocation:

    • NEWBUFFER MUST create a new buffer of the specified size
    • If the specified size is negative or exceeds implementation limits, the VM MUST enter the FAULT state
  2. Memory Copy Operations:

    • MEMCPY MUST validate source and destination buffer bounds before performing the copy
    • If source or destination ranges are invalid, the VM MUST enter the FAULT state
    • MEMCPY MUST support overlapping ranges in the same buffer (moving data properly)
  3. String Operations:

    • String operations MUST work consistently on both ByteString and Buffer types
    • Index parameters MUST be zero-based
    • If an index is out of bounds, the VM MUST enter the FAULT state
    • String operations that produce a new string MUST create a new ByteString instance

5.7 Comparison Operations

Comparison operations compare values on the stack:

OpCode Hex Operand Size Description Stack [top first]
EQUAL 0xD0 0 bytes Check if two values are equal x₁ x₂ → bool
NOTEQUAL 0xD1 0 bytes Check if two values are not equal x₁ x₂ → bool
GT 0xD2 0 bytes Check if first value is greater than second x₁ x₂ → bool
GTE 0xD3 0 bytes Check if first value is greater or equal x₁ x₂ → bool
LT 0xD4 0 bytes Check if first value is less than second x₁ x₂ → bool
LTE 0xD5 0 bytes Check if first value is less or equal x₁ x₂ → bool

5.7.1 Comparison Operation Requirements

A conforming implementation MUST ensure the following for comparison operations:

  1. Type Compatibility:

    • Comparison operations MUST attempt to convert operands to compatible types if they differ
    • If conversion is not possible, the VM MUST enter the FAULT state
  2. Equality Comparison:

    • EQUAL and NOTEQUAL MUST follow the equality rules defined in section 3.5
    • EQUAL MUST return TRUE if two references point to the same object
    • EQUAL MUST perform deep comparison for complex types
  3. Ordering Comparison:

    • GT, GTE, LT, LTE MUST follow a consistent ordering for each type
    • Numeric types MUST be compared by their numeric value
    • String types MUST be compared lexicographically byte-by-byte
    • If types cannot be ordered (e.g., comparing a Map and an Array), the VM MUST enter the FAULT state

5.8 Arithmetic Operations

Arithmetic operations perform numeric calculations:

OpCode Hex Operand Size Description Stack [top first]
INC 0xC0 0 bytes Increment top numeric value by 1 x → x+1
DEC 0xC1 0 bytes Decrement top numeric value by 1 x → x-1
SIGN 0xC2 0 bytes Push the sign of top numeric value (-1, 0, 1) x → sign(x)
NEGATE 0xC3 0 bytes Negate top numeric value x → -x
ABS 0xC4 0 bytes Push absolute value of top numeric value x → abs(x)
NOT 0xC5 0 bytes Boolean NOT operation on top value x → !x
NZ 0xC6 0 bytes Push TRUE if top numeric value is not zero x → bool
ADD 0xC7 0 bytes Add two numeric values x₁ x₂ → x₁+x₂
SUB 0xC8 0 bytes Subtract second from top value x₁ x₂ → x₁-x₂
MUL 0xC9 0 bytes Multiply two numeric values x₁ x₂ → x₁*x₂
DIV 0xCA 0 bytes Divide first by second value x₁ x₂ → x₁/x₂
MOD 0xCB 0 bytes Remainder after division x₁ x₂ → x₁%x₂
POW 0xCC 0 bytes Raise first value to power of second x₁ x₂ → x₁^x₂
SHL 0xCD 0 bytes Left shift x₁ x₂ → x₁<<x₂
SHR 0xCE 0 bytes Right shift x₁ x₂ → x₁>>x₂
MIN 0xCF 0 bytes Get minimum of two values x₁ x₂ → min(x₁,x₂)
MAX 0xD0 0 bytes Get maximum of two values x₁ x₂ → max(x₁,x₂)

5.8.1 Arithmetic Operation Requirements

A conforming implementation MUST ensure the following for arithmetic operations:

  1. Type Compatibility:

    • Arithmetic operations MUST only be performed on compatible numeric types
    • If operands are of incompatible types, the VM MUST attempt type conversion according to section 3.4
    • If conversion fails, the VM MUST enter the FAULT state
  2. Numeric Overflow and Underflow:

    • Integer operations that would result in overflow/underflow MUST use wrap-around semantics
    • Overflow in operations on BigInteger types MUST expand the bit width to accommodate the result
  3. Division by Zero:

    • DIV and MOD operations with a zero divisor MUST cause the VM to enter the FAULT state
  4. Boolean Operations:

    • NOT operation MUST convert the operand to Boolean if it is not already a Boolean

5.8.2 Formal Operational Semantics for Arithmetic Operations

The following formal semantics define precisely how arithmetic operations transform the VM state:

// ADD operation
           S = [..., a, b], IsNumeric(a), IsNumeric(b)
---------------------------------------------------------------- [ADD]
E ⊢ ⟨σ, μ, ι = ADD, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a + b]⟩

// SUB operation
           S = [..., a, b], IsNumeric(a), IsNumeric(b)
---------------------------------------------------------------- [SUB]
E ⊢ ⟨σ, μ, ι = SUB, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a - b]⟩

// MUL operation
           S = [..., a, b], IsNumeric(a), IsNumeric(b)
---------------------------------------------------------------- [MUL]
E ⊢ ⟨σ, μ, ι = MUL, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a * b]⟩

// DIV operation
           S = [..., a, b], IsNumeric(a), IsNumeric(b), b ≠ 0
---------------------------------------------------------------- [DIV]
E ⊢ ⟨σ, μ, ι = DIV, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a / b]⟩

// DIV operation (division by zero)
           S = [..., a, b], IsNumeric(a), IsNumeric(b), b = 0
---------------------------------------------------------------- [DIV-ZERO]
E ⊢ ⟨σ, μ, ι = DIV, S⟩ ⟹ ⟨σ(FAULT), μ, ι, S⟩

// MOD operation
           S = [..., a, b], IsNumeric(a), IsNumeric(b), b ≠ 0
---------------------------------------------------------------- [MOD]
E ⊢ ⟨σ, μ, ι = MOD, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a % b]⟩

// MOD operation (division by zero)
           S = [..., a, b], IsNumeric(a), IsNumeric(b), b = 0
---------------------------------------------------------------- [MOD-ZERO]
E ⊢ ⟨σ, μ, ι = MOD, S⟩ ⟹ ⟨σ(FAULT), μ, ι, S⟩

// INC operation
           S = [..., a], IsNumeric(a)
---------------------------------------------------------------- [INC]
E ⊢ ⟨σ, μ, ι = INC, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a + 1]⟩

// DEC operation
           S = [..., a], IsNumeric(a)
---------------------------------------------------------------- [DEC]
E ⊢ ⟨σ, μ, ι = DEC, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., a - 1]⟩

// NEGATE operation
           S = [..., a], IsNumeric(a)
---------------------------------------------------------------- [NEGATE]
E ⊢ ⟨σ, μ, ι = NEGATE, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., -a]⟩

Where:

  • E is the execution environment
  • σ is the current VM state
  • μ is the memory state
  • ι is the instruction being executed
  • S is the current evaluation stack
  • S' is the resulting stack after the operation
  • next(ι) is the next instruction after ι
  • IsNumeric(x) is a predicate that checks if x can be interpreted as a numeric value
  • σ(FAULT) denotes the VM state changed to FAULT

5.8.3 Arithmetic State Transition Table

The following table precisely defines the state transition for arithmetic operations:

Operation Pre-State (Stack Top→Bottom) Post-State (Stack Top→Bottom) Special Conditions
ADD x₁, x₂, ... (x₁+x₂), ... -
SUB x₁, x₂, ... (x₁-x₂), ... -
MUL x₁, x₂, ... (x₁*x₂), ... -
DIV x₁, x₂, ... (x₁/x₂), ... If x₂=0: FAULT
MOD x₁, x₂, ... (x₁%x₂), ... If x₂=0: FAULT
POW x₁, x₂, ... (x₁^x₂), ... -
SHL x₁, x₂, ... (x₁<<x₂), ... -
SHR x₁, x₂, ... (x₁>>x₂), ... -
MIN x₁, x₂, ... min(x₁,x₂), ... -
MAX x₁, x₂, ... max(x₁,x₂), ... -
INC x, ... (x+1), ... -
DEC x, ... (x-1), ... -
NEGATE x, ... (-x), ... -
ABS x, ... x
SIGN x, ... sign(x), ... -

Where sign(x) returns:

  • -1 if x < 0
  • 0 if x = 0
  • 1 if x > 0

These formal semantics ensure that arithmetic operations are implemented consistently across all Neo VM implementations.

5.9 Compound Type Operations

Compound type operations create and manipulate complex data structures:

OpCode Hex Operand Size Description Stack [top first]
NEWARRAY0 0xE0 0 bytes Create a new empty array → array
NEWARRAY 0xE1 0 bytes Create a new array with n items from stack item₁ ... itemₙ n → array
NEWARRAY_T 0xE2 1 byte Create a new array with n items of type T n → array
NEWSTRUCT0 0xE3 0 bytes Create a new empty struct → struct
NEWSTRUCT 0xE4 0 bytes Create a new struct with n items from stack item₁ ... itemₙ n → struct
NEWMAP 0xE5 0 bytes Create a new map → map
SIZE 0xE6 0 bytes Get size of array, struct, map or string x → size
HASKEY 0xE7 0 bytes Check if map or struct has a key container key → bool
KEYS 0xE8 0 bytes Get all keys in a map map → array
VALUES 0xE9 0 bytes Get all values in a map or struct container → array
PICKITEM 0xEA 0 bytes Get item at index from array, struct, or map container key → item
APPEND 0xEB 0 bytes Append an item to an array array item → array
SETITEM 0xEC 0 bytes Set item at index in array, struct, or map container key value → ø
REVERSEITEMS 0xED 0 bytes Reverse the order of items in array or struct container → container
REMOVE 0xEE 0 bytes Remove item at key from map or struct container key → ø
CLEARITEMS 0xEF 0 bytes Remove all items from container container → container

5.9.1 Compound Type Operation Requirements

A conforming implementation MUST ensure the following for compound type operations:

  1. Creation Operations:

    • NEWARRAY/NEWSTRUCT with a negative count MUST cause the VM to enter the FAULT state
    • NEWARRAY_T MUST create an array where all elements are initialized to the default value for the specified type
    • NEWMAP MUST create an empty map container
  2. Access Operations:

    • PICKITEM MUST validate that the key or index is valid for the container
    • For array and struct access, the index MUST be an integer within bounds
    • For map access, the key MUST be of a valid key type
    • If an invalid key or index is provided, the VM MUST enter the FAULT state
  3. Modification Operations:

    • APPEND MUST increase the size of the array by 1
    • SETITEM MUST replace the value at the specified key or index
    • REMOVE MUST decrease the size of the container by 1 and properly adjust internal structures
    • CLEARITEMS MUST remove all elements but preserve the container itself
  4. Container-Specific Operations:

    • HASKEY MUST return TRUE if the specified key exists in the container, FALSE otherwise
    • KEYS MUST return a new array containing all keys in a map
    • VALUES MUST return a new array containing all values in the container
    • REVERSEITEMS MUST reverse the order of elements in an array or struct in-place

5.9.2 Formal Operational Semantics for Compound Type Operations

The following formal semantics define precisely how compound type operations transform the VM state:

// NEWARRAY0 operation (create empty array)
---------------------------------------------------------------- [NEWARRAY0]
E ⊢ ⟨σ, μ, ι = NEWARRAY0, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Array()]⟩

// NEWARRAY operation (create array with n items)
           S = [..., i₁, i₂, ..., iₙ, n], n ≥ 0
---------------------------------------------------------------- [NEWARRAY]
E ⊢ ⟨σ, μ, ι = NEWARRAY, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Array(i₁, i₂, ..., iₙ)]⟩

// NEWARRAY_T operation (create typed array)
           S = [..., n], n ≥ 0, T is valid type (from opcode operand)
---------------------------------------------------------------- [NEWARRAY_T]
E ⊢ ⟨σ, μ, ι = NEWARRAY_T, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Array_T(n)]⟩

// NEWSTRUCT0 operation (create empty struct)
---------------------------------------------------------------- [NEWSTRUCT0]
E ⊢ ⟨σ, μ, ι = NEWSTRUCT0, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Struct()]⟩

// NEWSTRUCT operation (create struct with n items)
           S = [..., i₁, i₂, ..., iₙ, n], n ≥ 0
---------------------------------------------------------------- [NEWSTRUCT]
E ⊢ ⟨σ, μ, ι = NEWSTRUCT, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Struct(i₁, i₂, ..., iₙ)]⟩

// NEWMAP operation (create empty map)
---------------------------------------------------------------- [NEWMAP]
E ⊢ ⟨σ, μ, ι = NEWMAP, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., new Map()]⟩

// SIZE operation (get container size)
           S = [..., c], IsContainer(c) ∨ IsString(c)
---------------------------------------------------------------- [SIZE]
E ⊢ ⟨σ, μ, ι = SIZE, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., Size(c)]⟩

// HASKEY operation (check if key exists)
           S = [..., c, k], IsContainer(c), ValidKey(c, k)
---------------------------------------------------------------- [HASKEY]
E ⊢ ⟨σ, μ, ι = HASKEY, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., HasKey(c, k)]⟩

// KEYS operation (get map keys)
           S = [..., m], IsMap(m)
---------------------------------------------------------------- [KEYS]
E ⊢ ⟨σ, μ, ι = KEYS, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., Keys(m)]⟩

// VALUES operation (get container values)
           S = [..., c], IsContainer(c)
---------------------------------------------------------------- [VALUES]
E ⊢ ⟨σ, μ, ι = VALUES, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., Values(c)]⟩

// PICKITEM operation (get item from container)
           S = [..., c, k], IsContainer(c), ValidKey(c, k), HasKey(c, k)
---------------------------------------------------------------- [PICKITEM]
E ⊢ ⟨σ, μ, ι = PICKITEM, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., GetItem(c, k)]⟩

// PICKITEM operation (invalid key)
           S = [..., c, k], IsContainer(c), ¬(ValidKey(c, k) ∧ HasKey(c, k))
---------------------------------------------------------------- [PICKITEM-INVALID]
E ⊢ ⟨σ, μ, ι = PICKITEM, S⟩ ⟹ ⟨σ(FAULT), μ, ι, S⟩

// APPEND operation (append to array)
           S = [..., a, v], IsArray(a)
---------------------------------------------------------------- [APPEND]
E ⊢ ⟨σ, μ, ι = APPEND, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., Append(a, v)]⟩

// SETITEM operation (set container item)
           S = [..., c, k, v], IsContainer(c), ValidKey(c, k)
---------------------------------------------------------------- [SETITEM]
E ⊢ ⟨σ, μ, ι = SETITEM, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [...]⟩

// SETITEM operation (invalid key)
           S = [..., c, k, v], IsContainer(c), ¬ ValidKey(c, k)
---------------------------------------------------------------- [SETITEM-INVALID]
E ⊢ ⟨σ, μ, ι = SETITEM, S⟩ ⟹ ⟨σ(FAULT), μ, ι, S⟩

// REVERSEITEMS operation (reverse container items)
           S = [..., c], IsContainer(c), CanReverse(c)
---------------------------------------------------------------- [REVERSEITEMS]
E ⊢ ⟨σ, μ, ι = REVERSEITEMS, S⟩ ⟹ ⟨σ, μ, next(ι), S' = [..., Reverse(c)]⟩

// REMOVE operation (remove item by key)
           S = [..., c, k], IsContainer(c), ValidKey(c, k), HasKey(c, k)
---------------------------------------------------------------- [REMOVE]
E ⊢ ⟨σ, μ, ι = REMOVE, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [...]⟩

// CLEARITEMS operation (clear all items)
           S = [..., c], IsContainer(c)
---------------------------------------------------------------- [CLEARITEMS]
E ⊢ ⟨σ, μ, ι = CLEARITEMS, S⟩ ⟹ ⟨σ, μ', next(ι), S' = [..., Clear(c)]⟩

Where:

  • E is the execution environment
  • $\sigma$ is the current VM state
  • $\mu$ is the memory state
  • $\mu'$ is the updated memory state after reference counting adjustments
  • $\iota$ is the instruction being executed
  • $S$ is the current evaluation stack
  • $S'$ is the resulting stack after the operation
  • next($\iota$) is the next instruction after $\iota$
  • IsContainer(c) is a predicate that checks if c is a container (Array, Struct, or Map)
  • IsArray(a) is a predicate that checks if a is an Array
  • IsMap(m) is a predicate that checks if m is a Map
  • IsString(s) is a predicate that checks if s is a String or Buffer
  • ValidKey(c, k) checks if k is a valid key type for container c
  • HasKey(c, k) checks if container c contains key k
  • CanReverse(c) checks if container c supports item reversal (Arrays and Structs)
  • Size(c) returns the number of elements in container c
  • Keys(m) returns a new Array containing all keys in Map m
  • Values(c) returns a new Array containing all values in container c
  • GetItem(c, k) returns the value at key k in container c
  • Append(a, v) appends value v to Array a and returns the modified array
  • Reverse(c) reverses the order of elements in container c and returns the modified container
  • Clear(c) removes all elements from container c and returns the empty container
  • $\sigma$(FAULT) denotes the VM state changed to FAULT

5.9.3 Reference Counting in Compound Operations

Compound type operations involve creating, copying, and modifying references to objects, requiring careful management of reference counts:

  1. Creation Operations (NEWARRAY, NEWSTRUCT, NEWMAP):

    • The newly created container's reference count is set to 1
    • The reference count of items placed in the new container is incremented (RC++)
  2. Access Operations (PICKITEM, KEYS, VALUES):

    • The reference count of the returned item is incremented (RC++)
    • For operations that return a new container (KEYS, VALUES), the container's reference count is set to 1
  3. Modification Operations (APPEND, SETITEM, REMOVE):

    • When inserting an item into a container, the item's reference count is incremented (RC++)
    • When replacing an item in a container, the old item's reference count is decremented (RC--) and the new item's is incremented (RC++)
    • When removing an item from a container, the item's reference count is decremented (RC--)

5.9.4 Compound Type State Transition Table

The following table precisely defines the state transitions for compound type operations:

Operation Pre-State (Stack Top→Bottom) Post-State (Stack Top→Bottom) Special Conditions
NEWARRAY0 ... array, ... -
NEWARRAY i₁, i₂, ..., iₙ, n, ... array, ... n≥0, RC++
NEWARRAY_T n, ... array, ... n≥0, RC++
NEWSTRUCT0 ... struct, ... -
NEWSTRUCT i₁, i₂, ..., iₙ, n, ... struct, ... n≥0, RC++
NEWMAP ... map, ... -
SIZE container, ... size, ... -
HASKEY container, key, ... bool, ... -
KEYS map, ... array, ... RC++
VALUES container, ... array, ... RC++
PICKITEM container, key, ... item, ... RC++, valid key required
APPEND array, item, ... array, ... item RC++
SETITEM container, key, value, ... ... value RC++, old value RC--
REVERSEITEMS container, ... container, ... Array or Struct only
REMOVE container, key, ... ... item RC--
CLEARITEMS container, ... container, ... All items RC--

Where:

  • RC++ indicates the reference count of an object is incremented
  • RC-- indicates the reference count of an object is decremented

These formal semantics ensure that compound type operations are implemented consistently across all Neo VM implementations, with proper reference counting to manage memory.

5.10 Control Flow Operations

Control flow operations manage the execution path of the VM:

OpCode Hex Operand Size Description Stack [top first]
JMP 0x40 2 bytes Jump to offset
JMPIF 0x41 2 bytes Jump if top item is true cond → ø
JMPIFNOT 0x42 2 bytes Jump if top item is false cond → ø
CALL 0x43 2 bytes Call function at offset
RET 0x44 0 bytes Return from function call
SYSCALL 0x45 4 bytes Call system function ... → ...
THROW 0x46 0 bytes Throw exception ex → ø
TRY 0x47 8 bytes Begin exception catching block
ENDTRY 0x48 4 bytes End exception catching block
ENDFINALLY 0x49 0 bytes End finally block
PUSHTRY 0x4A 2 bytes Push address for try/catch to catch stack
POPTRY 0x4B 0 bytes Pop address from catch stack

5.10.1 Control Flow Operation Requirements

A conforming implementation MUST ensure the following for control flow operations:

  1. Jump Validation:

    • Jump targets MUST be valid instruction pointers within the current context's script
    • Jump targets MUST not be in the middle of an instruction
    • If a jump target is invalid, the VM MUST enter the FAULT state
  2. Call Stack Management:

    • CALL MUST create a new execution context with the same script
    • CALL MUST set the instruction pointer to the target offset
    • CALL MUST preserve the evaluation stack of the calling context
    • RET MUST destroy the current execution context and return to the caller
    • The VM MUST enforce MaxInvocationStackSize to prevent stack overflow
  3. Exception Handling:

    • TRY/CATCH/FINALLY blocks MUST follow proper nesting rules
    • THROW MUST push the exception to the exception handling stack
    • THROW MUST trigger the appropriate catch handler if one exists
    • The VM MUST enforce MaxTryNestingDepth to prevent abuse
    • ENDFINALLY MUST determine whether to continue execution or re-throw an exception
  4. System Calls:

    • SYSCALL MUST validate that the requested system function exists
    • SYSCALL MUST verify that parameters meet the function's requirements
    • SYSCALL MUST properly handle any errors that occur during execution
    • If a system call fails, the VM MUST enter the FAULT state

6. Engine Limits and Restrictions

6.1 Execution Engine Limits

A conforming implementation of the Neo VM MUST include a comprehensive set of limits to prevent resource abuse and ensure deterministic execution across different implementations.

6.1.1 Required Execution Limits

The following limits MUST be enforced by all compliant Neo VM implementations:

Limit Name Default Value Description
MaxStackSize 2048 Maximum number of items allowed on an evaluation stack
MaxInvocationStackSize 1024 Maximum depth of the call stack (nested calls)
MaxTryNestingDepth 16 Maximum nesting level of try/catch/finally blocks
MaxArraySize 1048576 Maximum number of elements in an array or map
MaxSlotsInBlock 1024 Maximum number of local variables and arguments
MaxItemSize 1048576 Maximum size of an item in bytes
MaxFunctionLength 65536 Maximum number of bytes in a function

6.1.2 Limit Enforcement Requirements

A conforming implementation MUST ensure the following for all execution limits:

  1. Limit Validation Points:

    • Stack size MUST be checked before any operation that would push items onto the stack
    • Invocation stack depth MUST be checked before any CALL operation
    • Try nesting depth MUST be checked before any TRY operation
    • Array/map size MUST be checked before any operation that would increase container size
    • Item size MUST be checked when creating or modifying items
  2. Violation Handling:

    • When a limit is exceeded, the VM MUST enter the FAULT state
    • The VM MUST provide a clear error message indicating which limit was exceeded
    • Execution MUST be halted immediately upon limit violation
  3. Configurability:

    • Implementations SHOULD allow these limits to be configurable
    • Implementations MAY enforce stricter limits than the defaults
    • Implementations MUST NOT enforce more permissive limits than the defaults in production environments
┌────────────────────────────────────────────────────────────────────┐
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│                       ┌─────────────────┐                          │
│                       │                 │                          │
│                       │   INITIALIZE    │                          │
│   │                   │                 │                   │      │
│   │                   └─────────────────┘                   │      │
│   │                           │                             │      │
│   │                           ▼                             │      │
│   │              ┌───────────────────────────┐              │      │
│   │              │                           │              │      │
│   │              │   INSTRUCTION EXECUTION   │              │      │
│   │              │                           │              │      │
│   │              └───────────────────────────┘              │      │
│   │                           │                             │      │
│   │                           ▼                             │      │
│   │                  ┌───────────────────┐                  │      │
│   │                  │                   │                  │      │
│   │                  │                   │                  │      │
│   │                  └───────────────────┘                  │      │
│   │                           │                             │      │
│   │                           ▼                             │      │
│   │                     ┌───────────┐                       │      │
│   │                     │           │                       │      │
│   │                     │           │                       │      │
│   │                     └───────────┘                       │      │
│   │                           │                             │      │
│   │                           ▼                             │      │
│   │                      ┌─────────┐                        │      │
│   │                      │Sufficient│                       │      │
│   │                      └─────────┘                        │      │
│   │                      /         \                        │      │
│   │             No      /           \     Yes               │      │
│   │           ┌────────┘             └────────┐             │      │
│   │           │                               │             │      │
│   │           ▼                               ▼             │      │
│   │    ┌─────────────┐                  ┌─────────────┐     │      │
│   │    │             │                  │             │     │      │
│   │    │  SET FAULT  │                  │  CONTINUE   ├─────┘      │
│   │    │    STATE    │                  │  EXECUTION  │            │
│   │    └─────────────┘                  └─────────────┘            │
│   │           │                                                    │
│   │           ▼                                                    │
│   │    ┌─────────────┐                                             │
│   │    │             │                                             │
│   │    │   END WITH  │                                             │
│   │    └─────────────┘                                             │
│   │                                                                │
│   └────────────────────────────────────────────────────────────────┘
│                                                                    │
└────────────────────────────────────────────────────────────────────┘
  1. Instruction Execution: As each instruction is executed:

    • Before operating on arrays, strings, or buffers, the VM MUST verify that the operation would not exceed size limits
    • All memory access operations MUST perform bounds checking
    • All slot access operations MUST verify slot indices are within the allocated range
  2. Resource Allocation Checks:

    • Before allocating slots, the VM MUST ensure the slot count is within the MaxSlotsInBlock limit
    • Before creating arrays or other containers, the VM MUST ensure size is within the MaxArraySize limit
    • Before storing data, the VM MUST ensure data size is within the MaxItemSize limit
  3. Data Validation:

    • Opcodes with operands MUST validate that the operands are valid
    • Jump targets MUST be validated to ensure they point to valid instructions
    • Type operations MUST validate that the type code is recognized by the system

6.2.2 Secure Execution Requirements

  1. Deterministic Execution:

    • Execution MUST be completely deterministic, with the same input always producing the same output
    • Random number generation and non-deterministic operations MUST be prohibited
    • Time-dependent operations MUST rely on blockchain time, not system time
  2. Isolation:

    • The VM MUST provide execution isolation from the host system
    • The VM MUST prevent direct access to system resources unless explicitly allowed
    • The VM MUST prevent leaking implementation details that could compromise security
  3. Resource Management:

    • The VM MUST properly clean up resources after execution completes or faults
    • The VM MUST maintain proper reference counting to prevent memory leaks
    • The VM MUST enforce strict limits on recursion and loop operations

To be considered conformant with this specification, an implementation MUST:

  1. Functional Requirements:

    • Correctly implement all VM components as described in this specification
    • Support all required opcodes with their specified behavior
    • Correctly handle type conversions, reference counting, and exception handling
  2. Security Requirements:

    • Implement all required security measures
    • Enforce all specified VM limits
    • Properly isolate VM execution from the host environment
  3. Determinism Requirements:

    • Ensure deterministic execution for all valid scripts
    • Produce identical results for identical inputs across different runs
    • Handle error conditions consistently according to this specification

7.2 Test Vectors

Implementations SHOULD be validated against standard test vectors that verify:

  1. Individual Opcode Tests:

    • Tests for each opcode verifying correct stack manipulation
    • Tests for edge cases and error conditions
    • Tests for type compatibility and conversion
  2. Integration Tests:

    • Tests for complex scripts combining multiple operations
    • Tests for exception handling scenarios
    • Tests for reference counting and memory management
  3. Limit Tests:

    • Tests that verify proper enforcement of VM limits
    • Tests that verify security isolation

7.3 Version Compatibility

Implementations SHOULD clearly indicate which version of the Neo VM specification they conform to. Future versions of this specification will include version numbers and change logs to track modifications.

8. Appendices

8.1 Opcode Reference Table

The following table provides a comprehensive reference of all Neo VM opcodes:

OpCode Hex Operand Size Description Stack [top first]
PUSHINT8 0x00 1 byte Push 1-byte signed integer onto stack → value
PUSHINT16 0x01 2 bytes Push 2-byte signed integer onto stack → value
PUSHINT32 0x02 4 bytes Push 4-byte signed integer onto stack → value
PUSHINT64 0x03 8 bytes Push 8-byte signed integer onto stack → value
PUSHINT128 0x04 16 bytes Push 16-byte signed integer onto stack → value
PUSHINT256 0x05 32 bytes Push 32-byte signed integer onto stack → value
PUSHT 0x08 0 bytes Push boolean True onto stack → True
PUSHF 0x09 0 bytes Push boolean False onto stack → False
PUSHA 0x0A 4 bytes Push pointer onto stack → ptr
PUSHNULL 0x0B 0 bytes Push null value onto stack → null
PUSHDATA1 0x0C 1 + n bytes Push n bytes onto stack (n < 256) → bytes
PUSHDATA2 0x0D 2 + n bytes Push n bytes onto stack (n < 65536) → bytes
PUSHDATA4 0x0E 4 + n bytes Push n bytes onto stack → bytes
PUSHM1 0x0F 0 bytes Push integer -1 onto stack → -1
PUSH0 0x10 0 bytes Push integer 0 onto stack → 0
PUSH1 0x11 0 bytes Push integer 1 onto stack → 1
PUSH2 0x12 0 bytes Push integer 2 onto stack → 2
PUSH3 0x13 0 bytes Push integer 3 onto stack → 3
PUSH4 0x14 0 bytes Push integer 4 onto stack → 4
PUSH5 0x15 0 bytes Push integer 5 onto stack → 5
PUSH6 0x16 0 bytes Push integer 6 onto stack → 6
PUSH7 0x17 0 bytes Push integer 7 onto stack → 7
PUSH8 0x18 0 bytes Push integer 8 onto stack → 8
PUSH9 0x19 0 bytes Push integer 9 onto stack → 9
PUSH10 0x1A 0 bytes Push integer 10 onto stack → 10
PUSH11 0x1B 0 bytes Push integer 11 onto stack → 11
PUSH12 0x1C 0 bytes Push integer 12 onto stack → 12
PUSH13 0x1D 0 bytes Push integer 13 onto stack → 13
PUSH14 0x1E 0 bytes Push integer 14 onto stack → 14
PUSH15 0x1F 0 bytes Push integer 15 onto stack → 15
PUSH16 0x20 0 bytes Push integer 16 onto stack → 16
NOP 0x21 0 bytes No operation
JMP 0x22 1 byte Unconditional jump to offset
JMP_L 0x23 4 bytes Unconditional jump to offset (long)
JMPIF 0x24 1 byte Jump if top item is true cond → ø
JMPIF_L 0x25 4 bytes Jump if top item is true (long) cond → ø
JMPIFNOT 0x26 1 byte Jump if top item is false cond → ø
JMPIFNOT_L 0x27 4 bytes Jump if top item is false (long) cond → ø
JMPEQ 0x28 1 byte Jump if two values are equal x1, x2 → ø
JMPEQ_L 0x29 4 bytes Jump if two values are equal (long) x1, x2 → ø
JMPNE 0x2A 1 byte Jump if two values are not equal x1, x2 → ø
JMPNE_L 0x2B 4 bytes Jump if two values are not equal (long) x1, x2 → ø
JMPGT 0x2C 1 byte Jump if first value > second value x1, x2 → ø
JMPGT_L 0x2D 4 bytes Jump if first value > second value (long) x1, x2 → ø
JMPGE 0x2E 1 byte Jump if first value >= second value x1, x2 → ø
JMPGE_L 0x2F 4 bytes Jump if first value >= second value (long) x1, x2 → ø
JMPLT 0x30 1 byte Jump if first value < second value x1, x2 → ø
JMPLT_L 0x31 4 bytes Jump if first value < second value (long) x1, x2 → ø
JMPLE 0x32 1 byte Jump if first value <= second value x1, x2 → ø
JMPLE_L 0x33 4 bytes Jump if first value <= second value (long) x1, x2 → ø
CALL 0x34 1 byte Call function at offset
CALL_L 0x35 4 bytes Call function at offset (long)
CALLA 0x36 0 bytes Call function at address from stack addr → ø
CALLT 0x37 2 bytes Call function by token
ABORT 0x38 0 bytes Set VM state to FAULT
ASSERT 0x39 0 bytes Exit if top value is false cond → ø
THROW 0x3A 0 bytes Throw an exception ex → ø
TRY 0x3B 2 bytes Begin try-catch-finally block
TRY_L 0x3C 8 bytes Begin try-catch-finally block (long)
ENDTRY 0x3D 1 byte End try block, jump to offset
ENDTRY_L 0x3E 4 bytes End try block, jump to offset (long)
ENDFINALLY 0x3F 0 bytes End finally block
RET 0x40 0 bytes Return from function call
SYSCALL 0x41 4 bytes Call system function ... → ...
DEPTH 0x43 0 bytes Get stack item count → n
DROP 0x45 0 bytes Remove top item from stack x → ø
NIP 0x46 0 bytes Remove second-to-top item from stack x1, x2 → x2
XDROP 0x48 0 bytes Remove the item n back from top ..., xn, ...x1, n → ..., ...x1
CLEAR 0x49 0 bytes Clear the entire stack ... → ø
DUP 0x4A 0 bytes Duplicate top item x → x, x
OVER 0x4B 0 bytes Copy second item to top x1, x2 → x1, x2, x1
PICK 0x4D 0 bytes Copy item n back to top ..., xn, ...x1, n → ..., xn, ...x1, xn
TUCK 0x4E 0 bytes Copy top item before second item x1, x2 → x2, x1, x2
SWAP 0x50 0 bytes Swap top two items x1, x2 → x2, x1
ROT 0x51 0 bytes Rotate top three items x1, x2, x3 → x2, x3, x1
ROLL 0x52 0 bytes Move item n back to top ..., xn, ...x1, n → ..., ...x1, xn
REVERSE3 0x53 0 bytes Reverse order of top 3 items x1, x2, x3 → x3, x2, x1
REVERSE4 0x54 0 bytes Reverse order of top 4 items x1, x2, x3, x4 → x4, x3, x2, x1
REVERSEN 0x55 0 bytes Reverse order of top n items ..., n → reverse(...)
INITSSLOT 0x56 1 byte Initialize static fields
INITSLOT 0x57 2 bytes Initialize local variables and arguments
LDSFLD0 0x58 0 bytes Load static field 0 → value
LDSFLD1 0x59 0 bytes Load static field 1 → value
LDSFLD2 0x5A 0 bytes Load static field 2 → value
LDSFLD3 0x5B 0 bytes Load static field 3 → value
LDSFLD4 0x5C 0 bytes Load static field 4 → value
LDSFLD5 0x5D 0 bytes Load static field 5 → value
LDSFLD6 0x5E 0 bytes Load static field 6 → value
LDSFLD 0x5F 1 byte Load static field at index → value
STSFLD0 0x60 0 bytes Store to static field 0 x → ø
STSFLD1 0x61 0 bytes Store to static field 1 x → ø
STSFLD2 0x62 0 bytes Store to static field 2 x → ø
STSFLD3 0x63 0 bytes Store to static field 3 x → ø
STSFLD4 0x64 0 bytes Store to static field 4 x → ø
STSFLD5 0x65 0 bytes Store to static field 5 x → ø
STSFLD6 0x66 0 bytes Store to static field 6 x → ø
STSFLD 0x67 1 byte Store to static field at index x → ø
LDLOC0 0x68 0 bytes Load local variable 0 → value
LDLOC1 0x69 0 bytes Load local variable 1 → value
LDLOC2 0x6A 0 bytes Load local variable 2 → value
LDLOC3 0x6B 0 bytes Load local variable 3 → value
LDLOC4 0x6C 0 bytes Load local variable 4 → value
LDLOC5 0x6D 0 bytes Load local variable 5 → value
LDLOC6 0x6E 0 bytes Load local variable 6 → value
LDLOC 0x6F 1 byte Load local variable at index → value
STLOC0 0x70 0 bytes Store to local variable 0 x → ø
STLOC1 0x71 0 bytes Store to local variable 1 x → ø
STLOC2 0x72 0 bytes Store to local variable 2 x → ø
STLOC3 0x73 0 bytes Store to local variable 3 x → ø
STLOC4 0x74 0 bytes Store to local variable 4 x → ø
STLOC5 0x75 0 bytes Store to local variable 5 x → ø
STLOC6 0x76 0 bytes Store to local variable 6 x → ø
STLOC 0x77 1 byte Store to local variable at index x → ø
LDARG0 0x78 0 bytes Load argument 0 → value
LDARG1 0x79 0 bytes Load argument 1 → value
LDARG2 0x7A 0 bytes Load argument 2 → value
LDARG3 0x7B 0 bytes Load argument 3 → value
LDARG4 0x7C 0 bytes Load argument 4 → value
LDARG5 0x7D 0 bytes Load argument 5 → value
LDARG6 0x7E 0 bytes Load argument 6 → value
LDARG 0x7F 1 byte Load argument at index → value
STARG0 0x80 0 bytes Store to argument 0 x → ø
STARG1 0x81 0 bytes Store to argument 1 x → ø
STARG2 0x82 0 bytes Store to argument 2 x → ø
STARG3 0x83 0 bytes Store to argument 3 x → ø
STARG4 0x84 0 bytes Store to argument 4 x → ø
STARG5 0x85 0 bytes Store to argument 5 x → ø
STARG6 0x86 0 bytes Store to argument 6 x → ø
STARG 0x87 1 byte Store to argument at index x → ø
NEWBUFFER 0x88 0 bytes Create new buffer size → buffer
MEMCPY 0x89 0 bytes Copy memory between buffers src, srcPos, dst, dstPos, len → ø
CAT 0x8B 0 bytes Concatenate two strings s1, s2 → s1+s2
SUBSTR 0x8C 0 bytes Get substring s, pos, len → sub
LEFT 0x8D 0 bytes Get left part of string s, len → left
RIGHT 0x8E 0 bytes Get right part of string s, len → right
INVERT 0x90 0 bytes Bitwise NOT x → ~x
AND 0x91 0 bytes Bitwise AND x1, x2 → x1&x2
OR 0x92 0 bytes Bitwise OR x1, x2 → x1|x2
XOR 0x93 0 bytes Bitwise XOR x1, x2 → x1^x2
EQUAL 0x97 0 bytes Equality comparison x1, x2 → x1==x2
NOTEQUAL 0x98 0 bytes Inequality comparison x1, x2 → x1!=x2
SIGN 0x99 0 bytes Get sign of number x → sign(x)
ABS 0x9A 0 bytes Absolute value x → abs(x)
NEGATE 0x9B 0 bytes Negate value x → -x
INC 0x9C 0 bytes Increment by 1 x → x+1
DEC 0x9D 0 bytes Decrement by 1 x → x-1
ADD 0x9E 0 bytes Addition a, b → a+b
SUB 0x9F 0 bytes Subtraction a, b → a-b
MUL 0xA0 0 bytes Multiplication a, b → a*b
DIV 0xA1 0 bytes Division a, b → a/b
MOD 0xA2 0 bytes Modulo a, b → a%b
POW 0xA3 0 bytes Power function a, b → a^b
SQRT 0xA4 0 bytes Square root x → sqrt(x)
MODMUL 0xA5 0 bytes Modular multiplication a, b, m → (a*b)%m
MODPOW 0xA6 0 bytes Modular exponentiation a, b, m → (a^b)%m
SHL 0xA8 0 bytes Shift left x, n → x<<n
SHR 0xA9 0 bytes Shift right x, n → x>>n
NOT 0xAA 0 bytes Boolean NOT x → !x
BOOLAND 0xAB 0 bytes Boolean AND a, b → a&&b
BOOLOR 0xAC 0 bytes Boolean OR a, b → a||b
NZ 0xB1 0 bytes Is non-zero x → x!=0
NUMEQUAL 0xB3 0 bytes Numeric equality a, b → a==b
NUMNOTEQUAL 0xB4 0 bytes Numeric inequality a, b → a!=b
LT 0xB5 0 bytes Less than a, b → a<b
LE 0xB6 0 bytes Less than or equal a, b → a<=b
GT 0xB7 0 bytes Greater than a, b → a>b
GE 0xB8 0 bytes Greater than or equal a, b → a>=b
MIN 0xB9 0 bytes Minimum value a, b → min(a,b)
MAX 0xBA 0 bytes Maximum value a, b → max(a,b)
WITHIN 0xBB 0 bytes Test if within range x, min, max → min<=x<max
PACKMAP 0xBE 0 bytes Create map from key-value pairs ..., n → map
PACKSTRUCT 0xBF 0 bytes Create struct from values ..., n → struct
PACK 0xC0 0 bytes Create array from values ..., n → array
UNPACK 0xC1 0 bytes Extract values from collection coll → ..., n
NEWARRAY0 0xC2 0 bytes Create empty array → array
NEWARRAY 0xC3 0 bytes Create array with null values n → array
NEWARRAY_T 0xC4 1 byte Create typed array n → array
NEWSTRUCT0 0xC5 0 bytes Create empty struct → struct
NEWSTRUCT 0xC6 0 bytes Create struct with zero values n → struct
NEWMAP 0xC8 0 bytes Create empty map → map
SIZE 0xCA 0 bytes Get collection size coll → size
HASKEY 0xCB 0 bytes Check if key exists in collection coll, key → bool
KEYS 0xCC 0 bytes Get all keys from map map → keys
VALUES 0xCD 0 bytes Get all values from map map → values
PICKITEM 0xCE 0 bytes Get item from collection by key/index coll, key → value
APPEND 0xCF 0 bytes Append to collection coll, item → coll
SETITEM 0xD0 0 bytes Set item in collection coll, key, value → coll
REVERSEITEMS 0xD1 0 bytes Reverse collection elements coll → coll
REMOVE 0xD2 0 bytes Remove item from collection coll, key → ø
CLEARITEMS 0xD3 0 bytes Clear all items from collection coll → ø
POPITEM 0xD4 0 bytes Remove and return last item from array array → item
ISNULL 0xD8 0 bytes Check if value is null x → bool
ISTYPE 0xD9 1 byte Check if value is of specified type x → bool
CONVERT 0xDB 1 byte Convert to specified type x → converted
ABORTMSG 0xE0 0 bytes Abort execution with message msg → ø
ASSERTMSG 0xE1 0 bytes Assert condition with message cond, msg → ø

8.2 Normative References

  1. Neo Blockchain Technical Whitepaper
  2. IEEE 754-2019 Standard for Floating-Point Arithmetic
  3. Unicode Standard, Version 13.0

8.3 Security Considerations

8.3.1 Deterministic Execution

A conforming implementation MUST guarantee deterministic execution, ensuring that:

  1. The same script with the same inputs MUST always produce the same result across different instances and platforms
  2. No operations MAY depend on non-deterministic factors such as system time, random number generation, or hardware-specific behavior
  3. All type conversions and operations MUST follow strictly defined rules to ensure consistent results

8.3.2 Resource Isolation

A conforming implementation MUST provide resource isolation, ensuring that:

  1. Scripts MUST NOT access resources outside their authorized context
  2. VM execution MUST NOT affect the stability or security of the host system
  3. Resource limits MUST be strictly enforced to prevent denial-of-service attacks
  4. Memory accessed by scripts MUST be properly isolated from VM implementation details

8.3.3 Exception Handling Requirements

A conforming implementation MUST implement exception handling that:

  1. Properly catches and processes all exceptions according to the TRY/CATCH/FINALLY semantics
  2. Maintains a complete and accurate exception state at all times
  3. Properly unwinds the stack and frees resources when exceptions occur
  4. Provides clear error information when execution enters the FAULT state

9. Conclusion

9.1 Implementation Guidelines

To ensure a successful Neo VM implementation, developers SHOULD:

  1. Follow Strict Conformance:

    • Implement all requirements marked as MUST
    • Consider all recommendations marked as SHOULD
    • Document any deviations from the specification
  2. Prioritize Security:

    • Implement thorough input validation
    • Enforce all security constraints
    • Conduct security audits of the implementation
  3. Ensure Determinism:

    • Verify deterministic execution through comprehensive testing
    • Compare results with reference implementations
    • Test across different platforms and environments

9.2 Version Information

This document is version 1.0 of the Neo VM Specification.

The Neo VM described in this specification is exclusively for Neo N3.

9.3 Future Directions

Future versions of this specification may address:

  1. Advanced Optimizations: Techniques for improving VM performance while maintaining compatibility
  2. Extended Type System: Additional types or type operations
  3. Function Libraries: Standard libraries and interoperability features
  4. Formal Verification: Methods for formally verifying Neo VM implementations

This specification will continue to evolve based on community feedback and practical implementation experience. Implementers are encouraged to participate in the Neo ecosystem to help shape the future of the Neo VM.

10. Interoperability

Interoperability defines how the Neo VM interfaces with external systems, particularly the Neo blockchain environment.

10.1 Interoperability Model

A conforming implementation MUST support the following interoperability features:

10.1.1 Interop Interface

  1. InteropInterface Type:

    • The VM MUST implement the InteropInterface type as specified in section 3.3
    • InteropInterface MUST serve as a bridge between the VM and the host environment
    • InteropInterface objects MUST encapsulate a reference to a host object
  2. Interface Isolation:

    • The VM MUST prevent direct access to host memory through the InteropInterface
    • All interactions with host objects MUST go through the SYSCALL mechanism
    • The VM MUST maintain isolation between the execution context and the host environment

10.2 System Calls

SYSCALL is the primary mechanism for interoperability between the VM and the host environment.

10.2.1 SYSCALL Implementation Requirements

  1. Call Convention:

    • SYSCALL MUST take an operand that uniquely identifies the service to call
    • The format of this operand MAY be implementation-specific, but MUST be consistent
    • Common formats include 4-byte service IDs or variable-length method names
  2. Parameter Handling:

    • SYSCALL MUST take parameters from the evaluation stack
    • SYSCALL MUST validate parameter count and types before execution
    • SYSCALL MUST push the return value onto the evaluation stack upon completion
  3. Error Handling:

    • If a system service is not found, the VM MUST enter the FAULT state
    • If parameters are invalid, the VM MUST enter the FAULT state
    • If a system service throws an exception, the VM MUST enter the FAULT state

10.3 Standard Interoperability Services

While specific interoperability services depend on the host environment, Neo blockchain implementations SHOULD provide the following standard service categories:

  1. Runtime Services:

    • Services for notifications, logging, and execution context information
    • Platform version and environment information
  2. Storage Services:

    • Persistent storage operations for contract data
    • Storage context management
    • Serialization/deserialization utilities
  3. Cryptographic Services:

    • Cryptographic hash functions (SHA-256, RIPEMD-160, etc.)
    • Signature verification (ECDSA, etc.)
    • Random number generation (if supported by the platform)
  4. Blockchain Services:

    • Access to blockchain data (blocks, transactions, etc.)
    • Access to transaction context
    • Access to contract information

10.4 Interoperability Registration

A conforming blockchain implementation MUST provide a mechanism to register interoperability services with the VM:

  1. Service Registration:

    • Each service MUST be uniquely identifiable
    • Each service MUST specify parameter types and return type
  2. Service Descriptor:

    • Each service SHOULD be described by metadata including:
      • Name: A descriptive name for the service
      • Parameter specification: Number and types of parameters
      • Return type: Expected return value type
      • Required flags: Permissions required to invoke the service

10.5 Cryptographic Operations in Neo N3

Cryptographic operations are provided through the interoperability layer using the SYSCALL mechanism. This architectural approach offers greater flexibility and extensibility.

10.5.1 Cryptographic Service Calls

Cryptographic operations are accessed through the following system calls:

Service Name Description Parameters Return
System.Crypto.CheckSig Verifies a signature against a public key (pubkey: ByteString, signature: ByteString) Boolean
System.Crypto.CheckMultisig Verifies multiple signatures against multiple public keys (pubkeys: Array, signatures: Array) Boolean
System.Crypto.SHA256 Computes SHA-256 hash of input data (data: ByteString) ByteString
System.Crypto.RIPEMD160 Computes RIPEMD-160 hash of input data (data: ByteString) ByteString
System.Crypto.VerifyWithECDsa Verifies an ECDSA signature (message: ByteString, pubkey: ByteString, signature: ByteString, curve: Integer) Boolean

These services are invoked using the SYSCALL opcode (0x41) with the appropriate service identifier.

10.5.2 Example: Signature Verification

To verify a signature in a Neo N3 smart contract:

// Push public key onto stack
PUSHDATA1 [public key bytes]

// Push signature onto stack
PUSHDATA1 [signature bytes]

// Call System.Crypto.CheckSig
SYSCALL 0x9936e1c9 // The numeric identifier for System.Crypto.CheckSig

11. Blockchain Integration

11.1 ApplicationEngine Requirements

When integrating the Neo VM with a blockchain environment, implementations SHOULD provide an ApplicationEngine that extends the base ExecutionEngine with the following capabilities:

11.1.1 Smart Contract Execution

  1. Contract Loading:

    • The ApplicationEngine MUST support loading NEF (Neo Executable Format) files
    • The ApplicationEngine MUST validate contract manifests before execution
    • The ApplicationEngine MUST enforce proper contract versioning
  2. Execution Triggers:

    • The ApplicationEngine MUST support different execution triggers:
      • Verification: For verifying signatures and conditions
      • Application: For normal contract invocations
      • System: For system-level operations

11.1.2 Blockchain Integration Services

  1. Storage Services:

    • The ApplicationEngine MUST provide a persistent storage mechanism for contracts
    • Storage operations MUST be atomic and consistent with blockchain state
    • Storage access MUST be properly authorized through the permission system
  2. Event Mechanisms:

    • The ApplicationEngine MUST support a notification system for contract events
    • Notifications MUST capture the contract context, event name, and arguments
    • Events MUST be properly propagated to the blockchain runtime
  3. Native Contract Integration:

    • The ApplicationEngine SHOULD provide access to native contracts
    • Native contracts MUST follow the same interface as user contracts
    • Native contracts MAY have optimized execution paths

11.2 Permission Model

A blockchain implementation of the Neo VM MUST implement a robust permission model:

  1. Call Flags:

    • The ApplicationEngine MUST support the following permission flags:
      • ReadOnly: Limits contracts to read-only operations
      • AllowCall: Allows contracts to call other contracts
      • AllowNotify: Allows contracts to generate notifications
      • AllowModifyStates: Allows contracts to modify storage
  2. Contract Permissions:

    • Contract manifests MUST declare required permissions
    • The ApplicationEngine MUST enforce that contracts only use declared permissions
    • Permission checks MUST be performed before executing sensitive operations
  3. Witness Verification:

    • The ApplicationEngine MUST verify appropriate authorization for sensitive operations
    • Witness checks MUST validate that required accounts have authorized the operation
    • The ApplicationEngine MUST maintain consistent authorization context during execution

12. References

  1. ISO/IEC 23271:2012 - Common Language Infrastructure (CLI), Partitions I to VI
  2. IEEE 754-2019 - Standard for Floating-Point Arithmetic
  3. Neo N3 Blockchain Protocol Specification
  4. RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels
  5. FIPS PUB 180-4 - Secure Hash Standard (SHS)
  6. FIPS PUB 186-4 - Digital Signature Standard (DSS)
  7. ANSI X9.62-2005 - Public Key Cryptography for the Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
  8. Automated Formal Verification of Smart Contracts, Zheng Yang, Hang Lei (2020)
  9. Neo Smart Contract Developer Guide, Neo Foundation (2023)
  10. NeoContract White Paper, Erik Zhang (2018)

13. Appendices

Appendix A: NeoVM Bytecode Reference

// ... existing bytecode content ...

Appendix B: Conformance Validation

B.1 Validation Test Suite

To validate that an implementation conforms to this specification, a comprehensive test suite is available at https://github.com/neo-project/neo-vm-conformance. This test suite includes tests for:

  1. Instruction Tests: Individual tests for each instruction in the Neo VM instruction set
  2. Type System Tests: Tests for type conversions and type system semantics
  3. Exception Handling Tests: Tests for try/catch/finally behavior
  4. Resource Limit Tests: Tests for memory and execution limits
  5. Reference Counting Tests: Tests for memory management and garbage collection
  6. Interoperability Tests: Tests for system call functionality

B.2 Conformance Certification Process

Implementations seeking conformance certification should follow this process:

  1. Run the Conformance Test Suite: Execute all tests in the conformance test suite against the implementation.
  2. Document Results: Record the results of all tests, noting any deviations from expected results.
  3. Document Extensions: Document any extensions or optional features implemented beyond the core specification.
  4. Provide Implementation Details: Supply information about the implementation environment, language, and any relevant optimization strategies.
  5. Submit for Review: Submit the implementation and test results for peer review.

B.3 Implementation Variations

This specification acknowledges that implementations may vary in the following ways while still conforming to the specification:

  1. Performance Optimizations: Implementations may include performance optimizations such as JIT compilation, as long as these optimizations do not alter the semantics of the VM.
  2. Resource Limit Implementation: Implementations may vary in how they enforce resource limits, as long as they enforce limits at least as strict as those specified.
  3. Error Reporting: Implementations may provide additional error reporting beyond the requirements of this specification.
  4. Extensions: Implementations may include extensions beyond the core specification, as long as these extensions do not alter the behavior of the core features.

Appendix C: Implementation Guidance

C.1 Strategy for New Implementations

When implementing the Neo VM from scratch, the following strategy is RECOMMENDED:

  1. Phase 1: Core VM Components

    • Implement the basic VM structure including execution engine, context, and stack management
    • Implement the type system with reference counting
    • Implement simple opcodes (constants, flow control, stack manipulation)
  2. Phase 2: Advanced Features

    • Implement arithmetic and bitwise operations
    • Implement array, struct, and map operations
    • Implement exception handling
  3. Phase 3: Interoperability and Optimization

    • Implement system call functionality
    • Apply performance optimizations
    • Integrate with blockchain environment (if applicable)

C.2 Performance Considerations

Implementers should consider the following performance optimizations:

  1. Instruction Dispatch: Efficient instruction dispatch is critical for VM performance. Consider the following approaches:

    • Direct threading: Use computed gotos (where available) for faster instruction dispatch
    • Inline caching: Cache frequently used dispatch targets
    • Superinstructions: Combine common instruction sequences into single operations
  2. Stack Operations: Optimize frequently used stack operations:

    • Implement stack reserving to minimize reallocations
    • Consider specialized handling for small integer constants
    • Optimize common stack patterns (e.g., DUP and DROP combinations)
  3. Memory Management:

    • Implement efficient reference counting with batched reclamation
    • Consider generational garbage collection for cyclic references
    • Pool common objects like small integers and empty containers
  4. JIT Compilation (Optional):

    • For high-performance implementations, consider JIT compilation of hot code paths
    • Apply type specialization based on runtime type information
    • Implement escape analysis to eliminate unnecessary reference counting

C.3 Common Implementation Pitfalls

Implementers should be aware of the following common pitfalls:

  1. Reference Counting Errors:

    • Failing to increment references when duplicating objects
    • Failing to decrement references when removing objects
    • Not handling cyclic references properly
  2. Type Conversion Issues:

    • Inconsistent conversion rules between types
    • Incorrect handling of edge cases (e.g., very large integers)
  3. Exception Handling Complexity:

    • Improper stack unwinding during exceptions
    • Memory leaks during exception propagation
  4. Determinism Violations:

    • Using non-deterministic operations like random number generation
    • Relying on platform-specific behavior

C.4 Example Implementation Patterns

// Example reference counting implementation pattern
public class StackItem
{
    private int _stackReferences = 0;
    private int _fieldReferences = 0;

    public void AddStackReference()
    {
        Interlocked.Increment(ref _stackReferences);
    }

    public void AddFieldReference()
    {
        Interlocked.Increment(ref _fieldReferences);
    }

    public void RemoveStackReference()
    {
        if (Interlocked.Decrement(ref _stackReferences) == 0 && _fieldReferences == 0)
            Recycle();
    }

    public void RemoveFieldReference()
    {
        if (Interlocked.Decrement(ref _fieldReferences) == 0 && _stackReferences == 0)
            Recycle();
    }

    protected virtual void Recycle()
    {
        // Release resources
    }
}

Appendix D: Glossary of Terms

D.1 Core Terminology

Array: A compound type that stores a sequence of stack items indexed by integers starting from 0.

Buffer: A stack item type that represents a mutable byte array with specialized operations.

ByteString: A stack item type representing an immutable sequence of bytes.

Context: An execution frame containing state for a script invocation

Execution Engine: The primary component responsible for executing scripts, maintaining the invocation stack and VM state.

Fault State: A VM state indicating that execution has terminated due to an error condition.

Halt State: A VM state indicating that execution has completed successfully.

Instruction: A single operation in the VM, consisting of an operation code and optional operand.

Interoperability: The ability of the VM to interact with the host environment

Invocation Stack: A stack data structure that maintains the ordered sequence of execution contexts.

Map: A compound type that stores a collection of key-value pairs, where keys and values are stack items.

Neo Executable Format (NEF): The binary format used to store Neo smart contracts for execution by the VM.

Reference Counting: A memory management technique used to track references to objects and reclaim memory when no references remain.

Script Container: An object that encapsulates a script to be executed by the VM.

Stack Item: The basic unit of data in the VM, representing various types such as integers, booleans, strings, arrays, etc.

Static Fields: Persistent storage accessible across multiple invocations of the same script.

Struct: A compound type that stores a collection of stack items indexed by integers similar to an array, but with value semantics for assignments.

System Call: A mechanism for the VM to call functions provided by the host environment.

D.2 Formal Verification Terminology

Assertion: A logical statement that must be true at a specific point in the program.

Invariant: A condition that holds true throughout the execution of a program or function.

Operational Semantics: A formal system that describes how the execution of a program happens step by step.

Precondition: A condition that must be true before a function is called for the function to behave correctly.

Postcondition: A condition that must be true after a function completes execution, assuming its precondition was met.

Safety Property: A property stating that "nothing bad happens" during execution.

Liveness Property: A property stating that "something good eventually happens" during execution.

State Transition: A change from one VM state to another as a result of executing an instruction.

Type Safety: The property that operations are only performed on data of appropriate types, preventing type errors during execution.

D.3 Blockchain-Specific Terminology

Application Engine: An extension of the execution engine that integrates with a blockchain environment.

Contract: A script deployed on the blockchain that can be invoked by transactions.

Native Contract: A contract implemented directly in the blockchain runtime rather than in VM bytecode.

Permission Flag: A flag that controls what operations a contract is allowed to perform.

Storage Context: An identifier that determines where a contract can read and write persistent data.

Witness: A proof that an account has authorized a specific operation.

Appendix E: Bytecode Format Reference

E.1 NEF File Format

The Neo Executable Format (NEF) is the standard binary format for Neo smart contracts. A NEF file consists of the following sections:

  1. Header: Contains the magic number, format version, and compiler information
  2. Script: Contains the bytecode to be executed by the VM
  3. Token: Contains a checksum of the file for validation

The detailed structure is as follows:

Note: The diagram below is ASCII art and displays best with a monospace font.

NEF File Structure:
┌───────────────┐
│    Header     │
├───────────────┤
│    Script     │
├───────────────┤
│     Token     │
└───────────────┘

Header Structure:
┌───────────────┬───────────────┬───────────────┬───────────────┐
│  Magic (4B)   │ Version (4B)  │  Compiler ID  │ Reserved (2B) │
└───────────────┴───────────────┴───────────────┴───────────────┘

Script Structure:
┌───────────────┬───────────────┐
│  Size (4B)    │  Bytecode     │
└───────────────┴───────────────┘

Token Structure:
┌───────────────┐
│ Checksum (8B) │
└───────────────┘

E.2 Script Section Encoding

The script section of a NEF file contains the VM bytecode to be executed. The bytecode is encoded as follows:

  1. Each instruction is encoded as an operation code (1 byte) followed by an optional operand.
  2. The operand size is determined by the operation code according to the following rules:
    • No operand (0 bytes): Most operations that manipulate the stack
    • Small operand (1 byte): Operations like JMP with small offsets
    • Medium operand (2-4 bytes): Operations with larger offsets or constants
    • Large operand (variable size): Operations like PUSHDATA with arbitrary data

E.3 Manifest Format

Accompanying the NEF file, a contract manifest provides metadata about the contract. The manifest is stored in JSON format and includes:

  1. Name: The name of the contract
  2. Groups: Security groups the contract belongs to
  3. Features: Features the contract supports (e.g., storage, payable)
  4. ABI: Application Binary Interface describing the contract's public methods
  5. Permissions: Required permissions for the contract
  6. Trusts: Other contracts that this contract trusts
  7. Extra: Additional metadata about the contract

Example manifest structure:

{
  "name": "ExampleContract",
  "groups": [],
  "features": {
    "storage": true,
    "payable": false
  },
  "abi": {
    "methods": [
      {
        "name": "main",
        "parameters": [
          {
            "name": "operation",
            "type": "String"
          },
          {
            "name": "args",
            "type": "Array"
          }
        ],
        "returntype": "Any"
      }
    ],
    "events": []
  },
  "permissions": [
    {
      "contract": "*",
      "methods": "*"
    }
  ],
  "trusts": [],
  "extra": null
}

@shargon
Copy link
Member

shargon commented Mar 8, 2025

Move to wiki?

@cschuchardt88
Copy link
Member

Move to wiki?

once you enable a wikki for this repo

@shargon
Copy link
Member

shargon commented Mar 8, 2025

Move to wiki?

once you enable a wikki for this repo

Done

@Wi1l-B0t
Copy link
Contributor

This doc is a specification.
But some of the content describes the implementation.
For exampe:

3.3.2 Stack Item Interface Visualization

May need to distinguish between implementation and specification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants