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与其他模块了解其他高级用途。
许可证
· 开源MIT (Github地址:/CityOfZion/neo-python/blob/master/LICENSE.md)
· 主作者为localhuman(Github地址:https://github.com/localhuman)
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
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..q_1[ ] [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对象。
对方法进行标记化后,各标记将在该方法内生成地址。生成完整的地址后,将调用convert_jumps方法来判断需跳转的流控制操作(地址)。
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复制代码
5 LOAD_CONST 'Main..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 ()复制代码
9 LOAD_CONST 3 ('Main..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]
某地址当前余额数值的返回方法
参数:account (bytearray) ——需获取余额的账户地址
返回值:某地址的当前余额
返回值类型: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]
NEP-5代币持有人将初始代币部署至自己地址的方法
返回值:部署成功与否
返回值类型:布尔值
boa.tests.src.NEP5Test.DoTransfer(t_from, t_to, amount)[source]
将一定量的NEP-5代币从一个账户转至另一个账户的方法
参数:
· t_from (bytearray) —— 转出地址
· t_to (bytearray) ——转入地址
· amount (int) ——待转账的NEP-5代币量
返回值:转账成功与否
返回值类型:布尔值
boa.tests.src.NEP5Test.Main(operation, args)[source]
此处是智能合约的主要入口点
参数:
· operation (str) —— 待执行的操作 如 mintTokens、transfer等)
· args (list) ——可选自变量列表
返回值:显示智能合约已成功执行
返回值类型:布尔值
boa.tests.src.NEP5Test.MintTokens()[source]
某地址将NEO存入NEP-5代币持有者的账户以换取一定量的NEP-5代币的调用方法
返回值:铸币成功与否
返回值类型:布尔值
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
评论
查看更多