Python compiler for the Neo Virtual Machine¶
The neo-boa
compiler is a tool for compiling Python files to the .avm
format for usage in the Neo Virtual Machine. The latter is used to execute contracts on the Neo Blockchain.
The compiler supports a subset of the Python language (in the same way that a Boa Contstrictor is a subset of the Python snake species.)
Overview¶
The neo-boa
compiler is a tool for compiling Python files to the .avm
format for usage in the Neo Virtual Machine. The latter is used to execute contracts on the Neo Blockchain.
The compiler supports a subset of the Python language (in the same way that a Boa Contstrictor is a subset of the Python snake species.)
What it currently does¶
- Compiles a subset of the Python language to the
.avm
format for use in the Neo Virtual Machine. - Works for Python 3.6+
- Support dictionary objects
- Adds debugging map for debugging in neo-python or other NEO debuggers
What will it do¶
- Compile a larger subset of the Python language.
What parts of Python are supported?¶
The following is a glimpse into the currently supported Python language features.
For details, please see all samples in the example
directory.
Flow Control:
- If, Else, Elif, While, Break, Method calls, for x in y.
Arithmetric and equality Operators for integer math:
- ADD, SUB, MUL, DIV, ABS, LSHIFT, RSHIFT, AND, OR, XOR, MODULO, INVERT, GT, GTE, LT, LTE, EQ, NOTEQ.
List creation is supported via a custom builtin. It should be noted that once created, a list length is not mutable.
from boa.code.builtins import list # this works x = list(length=10) x[3] = 84 # this also works x = [1,3,65,23] x.append('neo') x.remove(1) x.reverse()
list manipulation (building slices) is supported for strings and byte arrays, but not for lists
x = [1,2,46,56] # this will not work y = x[1:3] x = bytearray(b'\x01\x02\x03\x04') # this will be bytearray(b'\x03\x04') k = x[1:3] # you must specify the end element of a slice, the following will not work z = x[1:] # instead, use this z = x[1:len(x)] # the -1 index of a list does also not work at the moment
Where possible, some of Python’s
__builtins__
have been implemented in a custom way for the Neo Virtual Machine.from boa.code.builtins import range xrange = range(1, 30) # this also works for i in range(2, 21): i = i + 1
What is not supported and why?¶
The current Neo Virtual Machine is not as complex as your average Python interpreter. Therefore, there are many items in Python’s standard __builtins__
library that cannot be compiled to an executable smart contract. It would thus not be wise, or even possible, to import your favorite python library to do some kind of work for you. It is instread advised that you write
everything you plan on using in a smart contract using the functionality listed above.
The
__builtins__
items listed below are not supported at the moment. Many of them are not supported because the would not be supported inside the Neo Virtual Machine, while a few of these items are not supported because they just have not yet been implemented in boa.'zip', 'type', 'tuple', 'super', 'str', 'slice', 'set', 'reversed', 'property', 'memoryview', 'map', 'list', 'frozenset', 'float', 'filter', 'enumerate', 'dict', 'divmod', 'complex', 'bytes', 'bool', 'int', 'vars', 'sum', 'sorted', 'round', 'setattr', 'getattr', 'rep', 'quit', 'print', 'pow', 'ord', 'oct', 'next', 'locals', 'license', 'iter', 'isinstance', 'issubclass', 'input', 'id', 'hex', 'help', 'hash', 'hasattr', 'globals', 'format', 'exit', 'exec', 'eval', 'dir', 'deleteattr', 'credits', 'copyright', 'compile', 'chr', 'callable', 'bin', 'ascii', 'any', 'all'
List comprehension expressions are also not currently supported. This is on the roadmap.
# this does NOT work m = [x for x in range(1,10)]
Class objects are currently not supported. Use dictionaries instead
Dictionaries are supported
d = { 'a': 10, 'b': 4 'j': mymethodCall(), 'q': [1,3,5] } qlist = d['q']
Installation¶
This version of the compiler requires Python 3.6 or later
Using pip¶
pip install neo-boa
Manually¶
Clone the repository and navigate into the project directory. Make a Python 3 virtual environment and activate it via
python3 -m venv venv
source venv/bin/activate
or to explicitly install Python 3.6,
virtualenv -p /usr/local/bin/python3.6 venv
source venv/bin/activate
Then install the requirements via
pip install -r requirements.txt
Basic Usage¶
The compiler may be used as follows
from boa.compiler import Compiler
Compiler.load_and_save('path/to/your/file.py')
For legacy purposes, if you wish to compile without NEP8 stack isolation functionality, you may do the following:
from boa.compiler import Compiler
Compiler.load_and_save('path/to/your/file.py', use_nep=False)
See boa.compiler.Compiler and other modules for more advanced usage.
License¶
- Open-source MIT.
- Main author is localhuman [ https://github.com/localhuman ].
Tests¶
All tests are located in boa_test/test
. Tests can be run with the following command python -m unittest discover boa_test
boa.compiler.Compiler¶
What follows are the details of the Compiler
implementation.
-
class
boa.compiler.
Compiler
[source]¶ The main compiler interface class.
The following loads a python file, compiles it to the .avm format and saves it alongside the python file.
from boa.compiler import Compiler Compiler.load_and_save('path/to/your/file.py') # return the compiler object for inspection compiler = Compiler.load('path/to/your/file.py') # retrieve the default module for inpection default_module = compiler.default # retreive the default/entry method for the smart contract entry_method = default_module.main
-
default
¶ Retrieve the default or ‘entry’ module.
Returns: the default boa.code.Module object or None upon exception
-
static
instance
()[source]¶ Retrieve the current instance of the Compiler object, if it exists, or create one.
Returns: the singleton instance of the Compiler object
-
static
load
(path, use_nep8=True)[source]¶ Call load to load a Python file to be compiled but not to write to .avm
Parameters: path – the path of the Python file to compile Returns: The instance of the compiler The following returns the compiler object for inspection.
from boa.compiler import Compiler compiler = Compiler.load('path/to/your/file.py')
-
static
load_and_save
(path, output_path=None, use_nep8=True)[source]¶ Call load_and_save to load a Python file to be compiled to the .avm format and save the result. By default, the resultant .avm file is saved along side the source file.
Parameters: - path – The path of the Python file to compile
- output_path – Optional path to save the compiled .avm file
Returns: the instance of the compiler
The following returns the compiler object for inspection
from boa.compiler import Compiler Compiler.load_and_save('path/to/your/file.py')
-
boa.code.module.Module¶
What follows are the details of the Module
implementation.
-
class
boa.code.module.
Module
(path: str, module_name='', to_import=['*'])[source]¶ -
-
abi_entry_point
= None¶
-
abi_methods
= {}¶
-
actions
= None¶
-
all_vm_tokens
= {}¶
-
app_call_registrations
= None¶
-
bc
= None¶
-
blocks
= None¶
-
cfg
= None¶
-
extra_instructions
¶
-
local_methods
¶
-
main
¶ Return the default method in this module.
Returns: the default method in this module Return type: boa.code.method.Method
-
method_by_name
(method_name)[source]¶ Look up a method by its name from the module
methods
list. :param method_name: the name of the method to look up :type method_name: strReturns: the method ( if it is found) Return type: boa.code.method.Method
-
methods
= None¶
-
module_name
= ''¶
-
orderered_methods
¶ An ordered list of methods
Returns: A list of ordered methods is this module Return type: list
-
path
= None¶
-
to_import
= None¶
-
to_s
()[source]¶ this method is used to print the output of the executable in a readable/ tokenized format. sample usage:
>>> from boa.compiler import Compiler >>> module = Compiler.load('./boa/tests/src/LambdaTest.py').default >>> module.write() >>> print(module.to_s()) 12 3 LOAD_CONST 9 [data] 4 STORE_FAST j [data] 22 11 LOAD_FAST j [data] 17 CALL_FUNCTION Main.<locals>.q_1 [<boa.code.pytoken.PyToken object at 0x10cb53c50>] [data] 22 20 STORE_FAST m [data] 24 27 243 b' ' [data] 3 30 LOAD_FAST m [data] 35 NOP [data] 36 241 [data] 37 242 [data] 38 RETURN_VALUE [data] 20 49 243 b' ' [data] 3 52 LOAD_FAST x [data] 57 LOAD_CONST 1 [data] 58 BINARY_ADD [data] 59 NOP [data] 60 241 [data] 61 242 [data] 62 RETURN_VALUE [data]
-
boa.code.method.Method¶
What follows are the details of the Method
implementation.
-
class
boa.code.method.
method
(module, block, module_name, extra)[source]¶ -
-
address
= 0¶
-
args
¶
-
block
= None¶
-
blocks
= []¶
-
bytecode
= None¶
-
code
= None¶
-
code_object
= None¶
-
dictionary_defs
= None¶
-
forloop_counter
¶
-
full_name
¶
-
id
¶
-
is_abi_decorator
¶
-
is_interop
¶
-
module
= None¶
-
module_name
= None¶
-
name
= None¶
-
scope
¶
-
stack_size
= 0¶
-
stacksize
¶
-
start_line_no
= None¶
-
tokenizer
= None¶
-
tokens
= []¶
-
vm_tokens
¶ Returns a list of all vm tokens in this method.
Returns: a list of vm tokens in this method Return type: list
-
boa.code.expression.Expression¶
What follows are the details of the Expression
implementation.
boa.code.pytoken.PyToken¶
What follows are the details of the PyToken
implementation.
-
class
boa.code.pytoken.
PyToken
(instruction, expression, index, fallback_ln)[source]¶ -
arg_str
¶
-
args
¶
-
expression
= None¶
-
file
¶
-
func_name
¶
-
index
= 0¶
-
instruction
= None¶
-
is_breakpoint
= False¶
-
is_dynamic_appcall
= False¶
-
jump_found
= False¶
-
jump_from
= None¶
-
jump_from_addr
= None¶
-
jump_from_addr_abs
¶
-
jump_target
= None¶
-
jump_to_addr
= None¶
-
jump_to_addr_abs
¶
-
lineno
¶
-
method_lineno
¶
-
method_name
¶
-
num_params
¶
-
pyop
¶
-
boa.code.vmtoken.VMToken¶
What follows are the details of the VMToken
implementation.
Sample Python Files¶
The following is a selection of examples included with this project. The remainder of them can be seen at boa_test/examples
. All the following items as well as other tests are tested at boa_test/tests
Addition¶
This example show how to add numbers. It is also an example of a smart contract that accepts multiple parameters (4).
Lists¶
This example shows how to create and manipulate lists.
Binary Operators¶
This example shows how to use binary operators.
NEP5 Token¶
This example shows how to create a NEP5 token.
NEP5 Standard¶
Author: Thomas Saunders Email: tom@neonexchange.org
Date: Dec 11 2017
[Interop] Neo Blockchain¶
The items below are used for gathering state data contained within the blockchain. Because all items below are implemented in the Neo Virtual Machine, their source is not available here. Please see the neo-python project if you want to know more about their exact implementation.
Blockchain¶
Header¶
A Header object contains all information about a block, except for the transaction data.
-
boa.interop.Neo.Header.
GetMerkleRoot
(header)[source]¶ gets the merkle root of the transactions contained in the block
-
boa.interop.Neo.Header.
GetNextConsensus
(header)[source]¶ gets the address where the next consensus will occur
-
boa.interop.Neo.Header.
GetPrevHash
(header)[source]¶ gets the hash of the previous header in the blockchain
Block¶
A Block object contains the transaction data for a block.
-
boa.interop.Neo.Block.
GetTransaction
(block, index)[source]¶ Get the transaction specified in a block
Parameters: - block – the block to get the transaction from
- index – the index of the transaction within the block
Account¶
The Account object represents an address on the blockchain.
Action¶
An Action object is used to register an action/event listener on the blockchain.
App¶
An App object used to call other contracts on the blockchain.
[Interop] Execution Engine¶
The items below are used for gathering reference about the current execution of the Neo Virtual Machine. Because all items below are implemented in the Neo Virtual Machine, their source is not available here. Please see the neo-python project if you want to know more about their exact implementation.
Methods¶
-
boa.interop.System.ExecutionEngine.
GetCallingScriptHash
()[source]¶ Get the hash of the script ( smart contract ) which began execution of the current script.
- Note: This method is implemented inside the Neo Virtual Machine.
Returns: the hash of the script ( smart contract ) which began execution of the current script Return type: bytearray
-
boa.interop.System.ExecutionEngine.
GetEntryScriptHash
()[source]¶ Get the hash of the script ( smart contract ) which began execution of the smart contract.
- Note: This method is implemented inside the Neo Virtual Machine.
Returns: the hash of the script ( smart contract ) which began execution of the smart contract Return type: bytearray
-
boa.interop.System.ExecutionEngine.
GetExecutingScriptHash
()[source]¶ Get the hash of the script ( smart contract ) which is currently being executed
- Note: This method is implemented inside the Neo Virtual Machine.
Returns: the hash of the script ( smart contract ) which is currently being executed Return type: bytearray
-
boa.interop.System.ExecutionEngine.
GetScriptContainer
()[source]¶ Return the current Script Container of a smart contract execution. This will be a
boa.blockchain.vm.Neo.Transaction
object.- Note: This method is implemented inside the Neo Virtual Machine.
Returns: the current ScriptContainer of a smart contract execution. Return type: boa.blockchain.vm.Neo.Transaction