编译合约¶
命令行编译器工具¶
Vyper 包含以下用于编译合约的命令行脚本
vyper
: 将 vyper 合约文件编译成IR
或字节码vyper-json
: 为编译器提供 JSON 接口
注意
使用 --help
标志可以详细了解如何使用这些脚本中的每一个。
vyper¶
vyper
提供对编译器的命令行访问。它可以生成各种输出,包括简单的二进制文件、AST、接口和源映射。
编译合约
$ vyper yourFileName.vy
使用 -f
标志指定要返回的输出格式。使用 vyper --help
查看完整输出选项列表。
$ vyper -f abi,bytecode,bytecode_runtime,ir,asm,source_map,method_identifiers yourFileName.vy
使用 -p
标志可以设置一个根路径,该路径在搜索要导入的接口文件时使用。如果没有给出,它将默认为当前工作目录。有关更多信息,请参见 搜索接口文件。
$ vyper -p yourProject yourProject/yourFileName.vy
存储布局¶
显示合约的默认存储布局
$ vyper -f layout yourFileName.vy
这将输出一个 JSON 对象,详细说明了由编译器确定的所有状态变量的位置。
覆盖合约的默认存储布局
$ vyper --storage-layout-file storageLayout.json yourFileName.vy
使用 --storage-layout-file
标志的输入必须与 vyper -f layout
命令的 .storage_layout
字段的格式匹配。
vyper-json¶
vyper-json
为编译器提供 JSON 接口。它需要一个 JSON 格式的输入,并以 JSON 格式的输出 返回编译结果。
通过 stdin
编译 JSON
$ vyper-json
从 JSON 文件编译
$ vyper-json yourProject.json
默认情况下,输出将发送到 stdout
。要重定向到文件,请使用 -o
标志
$ vyper-json -o compiled.json
在线编译器¶
尝试 VyperLang!¶
尝试 VyperLang! 是一个由 Vyper 团队托管的 JupterHub 实例,作为在 Vyper 中开发和测试合约的沙箱。它需要 github 进行登录,并支持通过浏览器进行部署。
编译器优化模式¶
vyper CLI 工具接受优化模式 "none"
、"codesize"
或 "gas"
(默认)。可以使用 --optimize
标志设置它。例如,调用 vyper --optimize codesize MyContract.vy
将编译合约,并优化代码大小。作为对气体和代码大小模式之间差异的粗略总结,在气体优化模式下,编译器将尝试生成尽可能减少气体的字节码(在一定程度上),包括
使用稀疏选择器表,该表优化气体而不是代码大小
内联一些常量,以及
尝试展开一些循环,特别是对于数据复制。
在代码大小优化模式下,编译器将努力通过以下方式最小化代码大小
使用密集选择器表
外联代码,以及
使用更多循环进行数据复制。
设置目标 EVM 版本¶
编译合约代码时,可以指定要编译的目标以太坊虚拟机版本,以访问或避免特定功能。可以使用源代码 pragma 或编译器选项指定版本。建议在需要灵活性时(例如,跨不同链轻松部署)使用编译器选项,而在需要字节码可重复性时(例如,在区块浏览器上验证代码)使用源代码 pragma。
注意
如果编译器选项指定的 evm 版本与源代码 pragma 冲突,则将引发异常,编译将不会继续。
例如,将以下 pragma 添加到合约中表示它应该为 EVM 的“上海”分叉编译。
#pragma evm-version shanghai
警告
为错误的 EVM 版本编译会导致错误、奇怪或失败的行为。请确保,尤其是在运行私有链时,使用匹配的 EVM 版本。
通过 vyper
CLI 编译时,可以使用 --evm-version
标志指定 EVM 版本选项
$ vyper --evm-version [VERSION]
使用 JSON 接口时,可以在 "settings"
字段中包含 "evmVersion"
键
{
"settings": {
"evmVersion": "[VERSION]"
}
}
目标选项¶
以下列出了支持的 EVM 版本,以及每个版本引入的编译器更改。每个版本之间不保证向后兼容性。
- istanbul¶
可以通过
chain.id
访问CHAINID
操作码使用
SELFBALANCE
操作码调用self.balance
气体估计更改了
SLOAD
和BALANCE
- berlin¶
气体估计更改了
EXTCODESIZE
、EXTCODECOPY
、EXTCODEHASH
、SLOAD
、SSTORE
、CALL
、CALLCODE
、DELEGATECALL
和STATICCALL
使用
@nonreentrant
标记的函数使用与针对柏林之前的合约不同的值(3 和 2)进行保护。可以通过
block.basefee
访问BASEFEE
- paris¶
弃用
block.difficulty
,取而代之的是它的新别名block.prevrandao
。
- shanghai(default)¶
编译器会自动生成
PUSH0
操作码,而不是PUSH1 0
- cancun(experimental)¶
使用
transient
关键字可以声明存在于瞬态存储中的变量使用
@nonreentrant
标记的函数使用 TLOAD/TSTORE 而不是 SLOAD/SSTORE 进行保护对于大多数内存操作,
MCOPY
操作码将由编译器自动生成。
编译器输入和输出 JSON 描述¶
尤其是在处理复杂或自动化的设置时,推荐使用 vyper-json 和 JSON 输入输出接口进行编译。
在可能的情况下,Vyper JSON 编译器格式遵循 Solidity 的格式。
输入 JSON 描述¶
以下示例描述了 vyper-json
的预期输入格式。当然,注释是不允许的,这里仅用于解释目的。
{
// Required: Source code language. Must be set to "Vyper".
"language": "Vyper",
// Required
// Source codes given here will be compiled.
"sources": {
"contracts/foo.vy": {
// Optional: keccak256 hash of the source file
"keccak256": "0x234...",
// Required: literal contents of the source file
"content": "@external\ndef foo() -> bool:\n return True"
}
},
// Optional
// Interfaces given here are made available for import by the sources
// that are compiled. If the suffix is ".vy", the compiler will expect
// a contract-as-interface using proper Vyper syntax. If the suffix is
// "abi" the compiler will expect an ABI object.
"interfaces": {
"contracts/bar.vy": {
"content": ""
},
"contracts/baz.json": {
"abi": []
}
},
// Optional
"settings": {
"evmVersion": "shanghai", // EVM version to compile for. Can be istanbul, berlin, paris, shanghai (default) or cancun (experimental!).
// optional, optimization mode
// defaults to "gas". can be one of "gas", "codesize", "none",
// false and true (the last two are for backwards compatibility).
"optimize": "gas",
// optional, whether or not the bytecode should include Vyper's signature
// defaults to true
"bytecodeMetadata": true,
// The following is used to select desired outputs based on file names.
// File names are given as keys, a star as a file name matches all files.
// Outputs can also follow the Solidity format where second level keys
// denoting contract names - all 2nd level outputs are applied to the file.
//
// To select all possible compiler outputs: "outputSelection: { '*': ["*"] }"
// Note that this might slow down the compilation process needlessly.
//
// The available output types are as follows:
//
// abi - The contract ABI
// ast - Abstract syntax tree
// interface - Derived interface of the contract, in proper Vyper syntax
// ir - intermediate representation of the code
// userdoc - Natspec user documentation
// devdoc - Natspec developer documentation
// evm.bytecode.object - Bytecode object
// evm.bytecode.opcodes - Opcodes list
// evm.deployedBytecode.object - Deployed bytecode object
// evm.deployedBytecode.opcodes - Deployed opcodes list
// evm.deployedBytecode.sourceMap - Deployed source mapping (useful for debugging)
// evm.methodIdentifiers - The list of function hashes
//
// Using `evm`, `evm.bytecode`, etc. will select every target part of that output.
// Additionally, `*` can be used as a wildcard to request everything.
//
"outputSelection": {
"*": ["evm.bytecode", "abi"], // Enable the abi and bytecode outputs for every single contract
"contracts/foo.vy": ["ast"] // Enable the ast output for contracts/foo.vy
}
}
}
输出 JSON 描述¶
以下示例描述了 vyper-json
的输出格式。当然,注释是不允许的,这里仅用于解释目的。
{
// The compiler version used to generate the JSON
"compiler": "vyper-0.1.0b12",
// Optional: not present if no errors/warnings were encountered
"errors": [
{
// Optional: Location within the source file.
"sourceLocation": {
"file": "source_file.vy",
"lineno": 5,
"col_offset": 11
},
// Mandatory: Exception type, such as "JSONError", "StructureException", etc.
"type": "TypeMismatch",
// Mandatory: Component where the error originated, such as "json", "compiler", "vyper", etc.
"component": "compiler",
// Mandatory ("error" or "warning")
"severity": "error",
// Mandatory
"message": "Unsupported type conversion: int128 to bool"
// Optional: the message formatted with source location
"formattedMessage": "line 5:11 Unsupported type conversion: int128 to bool"
}
],
// This contains the file-level outputs. Can be limited/filtered by the outputSelection settings.
"sources": {
"source_file.vy": {
// Identifier of the source (used in source maps)
"id": 0,
// The AST object
"ast": {},
}
},
// This contains the contract-level outputs. Can be limited/filtered by the outputSelection settings.
"contracts": {
"source_file.vy": {
// The contract name will always be the file name without a suffix
"source_file": {
// The Ethereum Contract ABI.
// See https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
"abi": [],
// Natspec developer documentation
"devdoc": {},
// Intermediate representation (string)
"ir": "",
// Natspec developer documentation
"userdoc": {},
// EVM-related outputs
"evm": {
"bytecode": {
// The bytecode as a hex string.
"object": "00fe",
// Opcodes list (string)
"opcodes": ""
},
"deployedBytecode": {
// The deployed bytecode as a hex string.
"object": "00fe",
// Deployed opcodes list (string)
"opcodes": "",
// The deployed source mapping as a string.
"sourceMap": ""
},
// The list of function hashes
"methodIdentifiers": {
"delegate(address)": "5c19a95c"
}
}
}
}
}
}
错误¶
每个错误都包含一个 component
字段,指示错误发生的阶段。
json
: 解析输入 JSON 时发生的错误。通常是由于无效的 JSON 或缺少必需的值导致的。parser
: 解析合约时发生的错误。通常是由于无效的 Vyper 语法导致的。compiler
: 编译合约时发生的错误。vyper
: Vyper 内部发生的意外错误。如果您遇到此类型的错误,请提交问题。
您也可以使用 --traceback
标志,在遇到错误时获得标准的 Python 追溯。