NEO Python编译器介绍

Posted NEO智能经济

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NEO Python编译器介绍相关的知识,希望对你有一定的参考价值。

neo-boa编译器介绍


neo-boa编译器可将Python文件编译为.avm格式,在Neo虚拟机中运行。NEO虚拟机可在Neo区块链上执行合约。


编译器支持Python语言子集(python语言子集与python的关系类似于蟒蛇与蟒属的关系)。


目前功能


·   将Python语言子集编译成.avm格式,在Neo虚拟机上运行。

·   适用于Python3.4与3.5


未来功能


·   编译更广泛的Python语言子集

·   适用于Python3.6


已支持的Python功能


下文为目前支持的Python功能一览。详细介绍请参见boa.tests.src目录中的案例。


·   流控制

If、Else、Elif、While、Break、Methodcalls、Lamdbas、for x in


·   用于整数运算的算数运算符与相等运算符

ADD、SUB、MUL、DIV、ABS、LSHIFT、RSHIFT、AND、OR、XOR、MODULO、INVERT、GT、GTE、LT、LTE、EQ、NOTEQ


·   使用自定义内置功能进行列表创建。注意列表一经创建,其长度便不可更改。

 ·   from boa.code.builtins import list

     ·   

     ·   # this works

     ·   x = list(length=10)

     ·   x[3] = 84

     ·   

     ·   # this also works

     ·   x = [1,3,65,23]

     ·   

     ·   # this does NOT work

     ·   x = [ ]

     ·   x.append(1)

     ·   

·    支持列表(building slices)操作

     ·   x = [1,2,46,56]

     ·   y = x[1:3]

     

·   在可能的情况下,Python的某些__builtins__已经根据NEO虚拟机的特点以自定义的方式实现


     ·   fromboa.code.builtins import range

     ·   

     ·   xrange = range(1, 30)

     ·   

     ·   # this also works

     ·   fori in range(2, 21):

     ·       i = i + 1


安装

使用pip

pipinstallneo-boa


手动安装

克隆存储库,进入项目目录后创建Python3虚拟环境,并通过以下指令激活。

python3 -mvenvvenv
sourcevenv/bin/activate


或单独安装Python3.5

virtualenv -p /usr/local/bin/python3.5venv
sourcevenv/bin/activate


接着,通过以下指令安装需求

pipinstall -rrequirements.txt


基本用途

编译器使用指南如下

fromboa.compiler import Compiler
Compiler.load_and_save('path/to/your/file.py')

参见boa.compiler.Compiler与其他模块了解其他高级用途。


许可证

 

boa.compiler.Compiler

下文将介绍Compiler的具体实现细则。



classboa.compiler.Compiler[source] 


主编译器接口类

通过下列程序加载python文件,编译为.avm格式,并与python文件存储在一个地方。


fromboa.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 smartcontract

entry_method = default_module.main


default

取回默认或“入口”模块。

返回值:默认反回值为boa.code.Module对象,异常时无返回值


staticinstance()[source]

取回当前编译器对象的实例(如有),否则创建一个实例

返回值:编译器对象的单个实例


staticload(path)[source]

调用load来加载需编译但无需写为.avm格式的Python文件

参数:path--Python文件的编译路径

返回值:编译器实例

用途:通过下述程序返回编译器对象进行检查

fromboa.compiler import Compiler

compiler = Compiler.load('path/to/your/file.py')


staticload_and_save(path, output_path=None)[source

调用load_and_save来加载需编译为.avm格式的Python文件,并保存结果。默认情况下,最终生成的.avm文件将与源文件存储在一个地方。

参数:

·     path——Python文件的编译路径

·     output_path——已编译的.avm文件的可选保存路径

返回值:返回编译器实例

用途:通过下述代码返回编译器对象进行检查

fromboa.compiler import Compiler

Compiler.load_and_save('path/to/your/file.py')


write()[source]

返回值:已编译的Python程序的字节串



staticwrite_file(data, path)[source]


通过指定路径将输出数据存储至文件系统

参数:

·     data——待写入磁盘的数据字节串

·     path——文件写入路径


boa.code.module.Module


下文将介绍Module的具体实现细则。

classboa.code.module.Module(path, module_name='', is_sys_module=False, items_to_import=None)[source] 


模块是包含代码对象的顶层组件。例如,在path/to/my/file.py的编译过程中,file.py中包含的项目即为模块。一个可执行项可包含多个模块。上述案例中的“默认”或“入口”模块即为file.py


调用Compiler.load_and_save('path/to/file.py')时会专门为file.py创建一个模块。若file.py导入了其他任何功能,那些模块也会被添加至可执行项中,并置于Module.loaded_modules属性中。


在模块被当做方法处理,方法被当做基本块处理,基本块被处理为标记后,主模块或default模块的write()方法即被调用,将可执行项写为字节串,返回磁盘并存储。


如果您想检查模块内容,可使用Compiler.load('path/to/file.py'),该功能将返回一个编译器实例。获取该实例后,您便可以访问编译器的default模块,从而访问该默认模块中装入的其他模块。


各模块(以及各方法对象)均包含byteplay3对象bp的引用,该对象包含可在Python解释器中显示的指令集。


您可对具备bp属性的任意对象调用print(module.bp.code),结果将输出一段Python解释器代码。


>>> fromboa.compiler import Compiler

>>> module = Compiler.load('./boa/tests/src/AddTest1.py').default

>>> print(module.bp.code)

2    1 LOAD_CONST    <byteplay3.Code object at 0x10cc3d6a0>

      2 LOAD_CONST     'Main'

      3 MAKE_FUNCTION   0

      4 STORE_NAME     Main

      5 LOAD_CONST     None

      6 RETURN_VALUE


对可执行项进行处理与标记化后,便会生成虚拟机标记集,虚拟机标记虽与byteplay3标记相类似,但仍存在显著区别。这些标记均包含在该模块的all_vm_tokens属性中。


您可调用module.to_s()来查看该程序,因为该程序已根据NEO虚拟机的特点进行了标记化。

>>> module.to_s()

4   31  LOAD_FAST       a       [data]

    36  LOAD_CONST      2       [data]

    37  BINARY_MULTIPL          [data]

    38  STORE_FAST      a2      [data]

6   45  LOAD_FAST       b       [data]

    50  LOAD_CONST      1       [data]

    51  BINARY_ADD              [data]

    52  STORE_FAST      b2      [data]

8   59  LOAD_FAST       c       [data]

   64  LOAD_CONST      2       [data]

    65  BINARY_TRUE_DIVIDE      [data]

   66  STORE_FAST      c2      [data]

10  73  LOAD_FAST       d       [data]

   78  LOAD_CONST      1       [data]

   79  BINARY_SUBTRACT         [data]

    80  STORE_FAST      d2      [data]

13  87  243             b''     [data]
3   90  LOAD_FAST       a2      [data]

    95  LOAD_FAST       b2      [data]

   100 BINARY_ADD              [data]

    101 LOAD_FAST       c2      [data]

   106 BINARY_ADD              [data]

   107 LOAD_FAST       d2      [data]

    112 BINARY_ADD              [data]

    113 NOP                     [data]

    114 241                     [data]

    115 242                     [data]

    116 RETURN_VALUE            [data]
   

add_method(method)[source


在模块中添加方法如下:

Parameters: method (boa.code.method.Method) ——模块中待添加的方法对象

返回值:显示是否已添加该方法

返回值类型:布尔值


build()[source


bp.code对象拆分成行,并合并多行,生成不同的项目。


link_methods()[source]



main


返回该模块的默认方法

返回值:该模块的默认方法

返回值类型:boa.code.method.Method


method_by_name(method_name)[source


在模块的methods列表中查找方法名称:param method_name:

待查找的方法名称:typemethod_name: str

返回值:方法(如有)

返回值类型:boa.code.method.Method


module_path


返回该模块的文件路径

返回值:模块路径

返回值类型:str


orderered_methods


方法序列表

返回值:该模块中的方法序列表

返回值类型:列表


process_action(lineset)[source


处理模块中的动作,样本如下,其目的类似于创建下列事件:


fromboa.blockchain.vm.Neo.Action import RegisterAction

 

# Register the action.

onRefund = RegisterAction('refund','to_address','amount')

 

# Dispatch an action.

onRefund(my_address,100)

参数:lineset (list) – 包含应用程序调用注册功能的行集


process_import(import_item)[source]


处理该模块中的导入语句

Parameters: import_item (boa.code.items.Import subclass) –


process_method(lineset)[source]


处理包含byteplay3代码对象的行集

参数:lineset (list) – 需处理与添加的行集


process_smart_contract_app_registration(lineset)[source


在智能合约中调用另一个智能合约时处理智能合约应用程序注册事宜:


fromboa.blockchain.vm.Neo.App import RegisterAppCall

 

# register the contract

otherContract = RegisterAppCall('contract_hash','param1','param2')

 

# call the contract

result = otherContract(a,b )

参数:lineset (list) – 包含应用程序调用注册功能的行集


split_lines()[source]


将模块中的行集拆分成可编译的对象集


to_s()[source


该方法的目的在于以可读/标记化的格式打印可执行项的输出值,样本如下:

>>> from boa.compiler import Compiler

>>> module = Compiler.load('./boa/tests/src/LambdaTest.py').default

>>> module.write()

>>> 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]


write()[source]  


将当前模块写入字节串

注:如果您使用的是Compiler.load('path/to/file.py'),执行module.write()调用后方可对模块进行检查。

返回值:代表当前模块的字节串

返回值类型:字节


write_methods()[source]


将当前模块的所有方法写入字节串

返回值:该模块中当前存在的所有方法的字节串

返回值类型:字节


boa.code.method.Method


下文为Method的具体实现细则。


classboa.code.method.Method(code_object, parent, make_func_name=None)[source]

方法是主功能单元。

任何方法均可给多个自变量赋予0值,并返回1。

各方法包含的行数不同, boa.code.block.Block对象数也不同,意味着功能单元是互不相关的。


每行可被拆分为独立的boa.code.pytoken.PyToken对象,这些对象即为Python解释器使用的标记。


之后,每行便可形成一个区块。一个完整的区块生成后,将经历一系列的处理进程,最终将转化为可被NEO虚拟机理解的语言。


区块处理完毕后,我们可将其串联在一起,并发送给VMTokenizer。

VMTokenizer负责将PyToken对象转化为VMToken对象。



args


返回该方法中的自变量列表

返回值:该方法的自变量列表

返回值类型:列表


code


返回byteplay3代码对象

返回值:该方法的byteplay3代码对象

返回值类型:byteplay3.Code


convert_jumps()[source]


转换流控制项目中发生的跳转,如if、else、forloops、while loops及for breaks

firstlineno

获取该方法的起始行号

返回值:起始行号

返回值类型:int


full_name


获取该方法的全称

返回值:该方法模块的命名空间名称

返回值类型:str


module


取回包含该方法的模块

返回值:包含该方法的模块

返回值类型:boa.code.module.Module


name


获取该方法的名称

返回值:该方法的名称

返回值类型:str


print()[source]


打印该方法的byteplay3对象在python解释器中的输出值,并与boa.code.method.Method.to_dis()输出值对比,您会发现两者间微妙的区别。

输出样本

>>> method.print()

      2   STORE_FAST    j

      12  1 LOAD_CONST  9

      14  4 LOAD_CONST  <byteplay3.Code object at 0x10cb5ec88>

          5 LOAD_CONST  'Main.<locals>.q'

          6 MAKE_FUNCTION   0

          7 STORE_FAST      q

      22  9 LOAD_FAST       q

          10 LOAD_FAST      j

          11 CALL_FUNCTION  1

          12 STORE_FAST     m

      24  14 LOAD_FAST      m

          15 RETURN_VALUE


process_block_groups()[source


获取并处理当前区块(类似于方法中的行),以便区块能被适当地标记化


read_initial_tokens()[source]


从byteplay3代码对象中获取初始标记集,并将其转化为区块


read_module_variables()[source]


获取所有模块的global变量,并允许该方法访问这些变量。


to_dis()[source]


打印该方法在python编译器中的输出值,并与boa.code.method.Method.print()的输出值对比,您会发现两者间微妙的区别。


>>> method.to_dis()

  3       STORE_FAST    0 (j)

12     0 LOAD_CONST    1 (9)

14     6 LOAD_CONST    2 (<code object q at 0x10cbbc810, file "./boa/tests/src/LambdaTest.py", line 14>)

        9 LOAD_CONST    3 ('Main.<locals>.q')

        12 MAKE_FUNCTION   0

        15 STORE_FAST      1 (q)

22     18 LOAD_FAST       1 (q)

        21 LOAD_FAST       0 (j)

        24 CALL_FUNCTION   1 (1 positional, 0 keyword pair)

        27 STORE_FAST      2 (m)

24     30 LOAD_FAST       2 (m)

        33 RETURN_VALUE


tokenize()[source]


将boa.code.pytoken.PyToken对象集转化为boa.code.vmtoken.VMToken对象。


total_lines


获取该方法的总行(即区块)数

返回值:总行数

返回值类型:int


total_module_variables


获取局部变量总数

返回值:该模块中的变量总数

返回值类型:int


vm_tokens


返回该方法中的虚拟机标记列表

返回值:该方法中的虚拟机标记列表

返回值类型:列表


write()[source]


将标记器当前的状态写为字节串

返回值:当前标记器的字节串

返回值类型:字节


Python文件样本


添加

本案例展示了如何添加数字,同时这也是一个可接受多个参数的智能合约案例(4)。

boa.tests.src.AddTest1.Main(a, b, c, d)[source]

参数:

·     a –

·     b –

·     c –

·     d –

返回值:


列表

本案例展示了如何创建与操作列表


boa.tests.src.ArrayTest.Main()[source]


返回值:


boa.tests.src.ArrayTest.get_items_from_range(items, index)[source]


参数:

·     items –

·     index –

返回值:


boa.tests.src.ArrayTest.get_thing()[source]


返回值:

二元操作符

本案例展示了如何使用二元操作符


boa.tests.src.BinopTest.Main(a, b, c, d)[source]


参数:

·     a –

·     b –

·     c –

·     d –

返回值:


NEP-5代币


本案例展示了如何生成NEP-5代币。

将该文件编译为.avm格式后,需检查其是否符合NEO区块链上实施的的NEP-5代币标准。

查看代币标准议案NEP-5代币标准议案:https://github.com/neo-project/proposals/blob/master/nep-5.mediawiki。


可通过以下步骤进行编译

>>> fromboa.compiler import Compiler

>>> Compiler.load_and_save('./boa/tests/src/NEP5Test.py')


下方为Python的编译实现

boa.tests.src.NEP5Test.BalanceOf(account)[source] 


返回值类型:int


boa.tests.src.NEP5Test.CurrentSwapRate()[source]


NEO/NEP-5代币的当前“费率”或兑换率计算方法

返回值:当前费率

返回值类型:int


boa.tests.src.NEP5Test.Decimals()[source] 


NEP-5代币小数点返回方法

返回值:NEP-5代币的小数点

返回值类型:int


boa.tests.src.NEP5Test.Deploy()[source]


返回值:部署成功与否

返回值类型:布尔值


boa.tests.src.NEP5Test.DoTransfer(t_from, t_to, amount)[source]


将一定量的NEP-5代币从一个账户转至另一个账户的方法

参数:

·     amount (int) ——待转账的NEP-5代币量

返回值:转账成功与否

返回值类型:布尔值


boa.tests.src.NEP5Test.Main(operation, args)[source]


此处是智能合约的主要入口点

参数:

·     operation (str) —— 待执行的操作 如 mintTokenstransfer等)

·     args (list) ——可选自变量列表

返回值:显示智能合约已成功执行

返回值类型:布尔值


boa.tests.src.NEP5Test.MintTokens()[source]


返回值:铸币成功与否

返回值类型:布尔值


boa.tests.src.NEP5Test.Name()[source]


NEP-5代币名称返回方法

返回值:代币名称

返回值类型:str


boa.tests.src.NEP5Test.Symbol()[source]


NEP-5代币符号返回方法

返回值:代币符号

返回值类型:str


boa.tests.src.NEP5Test.TotalSupply()[source]


流通中的NEP-5代币总量数值返回方法

返回值:流通中的代币总量

返回值类型:int

 

【交互操作】NEO区块链


下列各操作的目的在于收集区块链中包含的状态数据。因为下列各项均是在NEO虚拟机中实现的,因此这里无法查找其源。若欲了解具体实现方法,请参考neo-python项目。


区块链



boa.blockchain.vm.Neo.Blockchain.GetAccount(script_hash) →boa.blockchain.vm.Neo.Account.Account[source] 


参数:script_hash –



boa.blockchain.vm.Neo.Blockchain.GetAsset(asset_id) →boa.blockchain.vm.Neo.Asset.Asset[source]


参数:asset_id –



boa.blockchain.vm.Neo.Blockchain.GetBlock(height_or_hash) →boa.blockchain.vm.Neo.Block.Block[source]


参数:height_or_hash –



boa.blockchain.vm.Neo.Blockchain.GetContract(script_hash) →boa.blockchain.vm.Neo.Contract.Contract[source]


参数:script_hash –



boa.blockchain.vm.Neo.Blockchain.GetHeader(height_or_hash) →boa.blockchain.vm.Neo.Header.Header[source]


参数:height_or_hash –



boa.blockchain.vm.Neo.Blockchain.GetHeight() → int[source]

boa.blockchain.vm.Neo.Blockchain.GetTransaction(hash) →boa.blockchain.vm.Neo.Transaction.Transaction[source]


参数:hash –



boa.blockchain.vm.Neo.Blockchain.GetValidators() → [][source]


区块头


区块头对象包含了所有区块信息,但不包含交易数据。



boa.blockchain.vm.Neo.Header.GetConsensusData(header: boa.blockchain.vm.Neo.Header.Header) →bytearray[source]



boa.blockchain.vm.Neo.Header.GetHash(header: boa.blockchain.vm.Neo.Header.Header) →bytearray[source]

获取区块头哈希值



boa.blockchain.vm.Neo.Header.GetMerkleRoot(header: boa.blockchain.vm.Neo.Header.Header) →bytearray[source]

获取区块中交易信息的默克尔根值



boa.blockchain.vm.Neo.Header.GetNextConsensus(header: boa.blockchain.vm.Neo.Header.Header) →bytearray[source]



boa.blockchain.vm.Neo.Header.GetPrevHash(header:boa.blockchain.vm.Neo.Header.Header) → bytearray[source]

获取区块链中上一个区块头的哈希值



boa.blockchain.vm.Neo.Header.GetTimestamp(header: boa.blockchain.vm.Neo.Header.Header) →int[source]

获取区块头创建时间戳



boa.blockchain.vm.Neo.Header.GetVersion(header: boa.blockchain.vm.Neo.Header.Header) →int[source]

获取区块头的版本号


区块


区块对象包含区块中的交易数据



boa.blockchain.vm.Neo.Block.GetTransaction(block:boa.blockchain.vm.Neo.Block.Block, index:int)→ boa.blockchain.vm.Neo.Transaction.Transaction[source]

参数:

·     block——包含该交易的区块

·     index——区块中交易的指数



boa.blockchain.vm.Neo.Block.GetTransactionCount(block: boa.blockchain.vm.Neo.Block.Block) →int[source]

返回区块中的交易数



boa.blockchain.vm.Neo.Block.GetTransactions(block:boa.blockchain.vm.Neo.Block.Block) → list[source]

返回区块中包含的交易列表


账户




boa.blockchain.vm.Neo.Account.GetBalance(account, asset_id)[source]

参数:

·     account –

·     asset_id –



boa.blockchain.vm.Neo.Account.GetScriptHash(account)[source]

参数:

account –



boa.blockchain.vm.Neo.Account.GetVotes(account)[source]

参数:

account –



boa.blockchain.vm.Neo.Account.SetVotes(account, votes)[source]

参数:

·    account –

·    votes –


动作


动作对象用于在区块链上注册动作/事件监听器



boa.blockchain.vm.Neo.Action.RegisterAction(event_name, *args)[source]

参数:

·     event_name –

·     args –


应用程序


应用程序对象用于调用区块链上的其他合约



boa.blockchain.vm.Neo.App.RegisterAppCall(smart_contract_hash, *args, **kwargs)[source]

参数:


·     smart_contract_hash –

·     args –

·     kwargs –


资产


资产对象用于检索NEO或GAS等本地资产信息



boa.blockchain.vm.Neo.Asset.Create(asset_type, name, amount, precision, owner, admin, issuer)[source]

参数:

·     asset_type –

·     name –

·     amount –

·     precision –

·     owner –

·     admin –

·     issuer –



boa.blockchain.vm.Neo.Asset.GetAdmin(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetAmount(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetAssetId(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetAssetType(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetAvailable(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetIssuer(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.GetOwner(asset)[source]

参数:

asset –


boa.blockchain.vm.Neo.Asset.GetPrecision(asset)[source]

参数:

asset –



boa.blockchain.vm.Neo.Asset.Renew(asset, years)[source]

参数:

·     asset –

·     years –


【交互操作】执行引擎


下列各操作的目的在于收集NEO虚拟机当前运行状态的参考数据。因为下列各项均是在NEO虚拟机中实现的,因此这里无法查找其出处。若欲了解具体实现方法,请参考neo-python项目。


方法




classboa.blockchain.vm.System.ExecutionEngine.ExecutionEngine[source]


未使用



boa.blockchain.vm.System.ExecutionEngine.GetCallingScriptHash()[source]


获取脚本(智能合约)的哈希值,开始执行当前脚本

返回值:脚本(智能合约)的哈希值,开始执行当前脚本

返回值类型:bytearray



boa.blockchain.vm.System.ExecutionEngine.GetEntryScriptHash()[source]


获取脚本(智能合约)的哈希值,开始执行智能合约

返回值:脚本(智能合约)的哈希值,开始执行智能合约

返回值类型:bytearray



boa.blockchain.vm.System.ExecutionEngine.GetExecutingScriptHash()[source]


获取执行中的脚本(智能合约)的哈希值

·   该方法在NEO虚拟机内部实现

返回值:执行中的脚本(智能合约)的哈希值

返回值类型:bytearray



boa.blockchain.vm.System.ExecutionEngine.GetScriptContainer()[source]


返回当前执行智能合约的Script Container,它是boa.blockchain.vm.Neo.Transaction对象

返回值:当前执行智能合约的Script  Container

返回值类型:boa.blockchain.vm.Neo.Transaction


原文出处:https://github.com/localhuman/neo-python


以上是关于NEO Python编译器介绍的主要内容,如果未能解决你的问题,请参考以下文章

Neo编译器

移植opencv3.4到Nanopi NEO 交叉编译

知识图谱Python.py2neo操作Neo4j

NEO C# 合约编译器原理解析

知识图谱使用Python驱动访问Neo4j

Python返回neo4j的中间路径