# VEP 17: 配额衡量
Vite 的虚拟机是在 EVM 的基础上扩展的,保留了 EVM 中燃料的概念。和 EVM 的燃料类似,在 Vite 中,通过配额来量化虚拟机执行代码时所消耗的计算资源和存储资源,并确保虚拟机在有限次执行内停机。
# 配额衡量依据
根据 Vite 链的特性和目前的实现细节,我们从以下几个方面衡量一笔交易或者一个虚拟机指令收取的配额:
- CPU 执行时间,即在稳定的环境下,这个操作需要执行多长时间;
- 历史数据,这类数据需要永久存储,但通常不提供链上查询,例如账户块数据、智能合约的 event 等;
- 状态存储,这类数据可以通过历史数据恢复,通常需要提供最新状态的查询,例如账户余额,合约状态等;
- 带宽,即需要在网络上传播的数据,例如网络块;
- 内存,虚拟机执行过程中占用的内存。
Vite 在代号为 SPROUT 的硬分叉修改了内置合约方法和虚拟机指令的配额消耗。
# 交易配额消耗表
交易名称 | 硬分叉后消耗配额 | 硬分叉前消耗配额 |
---|---|---|
Request | 21000 + 68×dataBytes | 21000 + 68×dataBytes |
Response | 21000 | 21000 |
CreateRequest | 31000 + 68×dataBytes | 21000 + 68×dataBytes |
CreateResponse | 31000 | 53000 |
PledgeRequest | 105000 | 82000 |
CancelPledgeRequest | 105000 | 73000 |
AgentPledgeRequest | 115500 | - |
AgentCancelPledgeRequest | 115500 | - |
RegisterRequest | 168000 | 62200 |
CancelRegisterRequest | 126000 | 83200 |
RewardRequest | 147000 | 68200 |
UpdateRegistrationRequest | 168000 | 62200 |
VoteRequest | 84000 | 62000 |
CancelVoteRequest | 52500 | 62000 |
MintRequest | 189000 | 104525 |
IssueRequest | 126000 | 69325 |
BurnRequest | 115500 | 48837 |
TransferOwnerRequest | 136500 | 58981 |
ChangeTokenTypeRequest | 115500 | 63125 |
GetTokenInfoRequest | 31500 | - |
DepositResponse | 10500 | - |
WithdrawResponse | 10500 | - |
NewmarketResponse | 31500 | - |
NeworderResponse | 25200 | - |
SettleorderResponse | 21000 | - |
PeriodjobResponse | 8400 | - |
PledgeforvxResponse | 31500 | - |
PledgeforvipResponse | 31500 | - |
PledgecallbackResponse | 12600 | - |
CancelpledgecallbackResponse | 16800 | - |
GettokenibfocallbackResponse | 10500 | - |
OwnerconfigResponse | 16800 | - |
OwnerconfigtradeResponse | 10500 | - |
MarketownerconfigResponse | 10500 | - |
TransfertokenownerResponse | 8400 | - |
NotifytimeResponse | 10500 | - |
NewinviterResponse | 18900 | - |
BindInviteCodeResponse | 8400 | - |
EndorseVxResponse | 6300 | - |
SettleMakerMinedVxResponse | 25200 | - |
# 虚拟机指令配额消耗表
指令代码 | 助记词 | 硬分叉后消耗配额 | 硬分叉前消耗配额 | 语义 |
---|---|---|---|---|
0x00 | STOP | 0 | 0 | 停止代码执行。 |
0x01 | ADD | 2 | 3 | 将两个操作数相加。 |
0x02 | MUL | 2 | 5 | 将两个操作数相乘。 |
0x03 | SUB | 2 | 3 | 将两个操作数相减。 |
0x04 | DIV | 3 | 5 | 将两个操作数相除,如除数为 0,则返回 0。 |
0x05 | SDIV | 5 | 5 | 带符号的整除。 |
0x06 | MOD | 3 | 5 | 求模操作。 |
0x07 | SMOD | 4 | 5 | 带符号的求模操作。 |
0x08 | ADDMOD | 4 | 8 | 先将前两个操作数相加,再与第三个操作数求模。 |
0x09 | MULMOD | 5 | 8 | 先将前两个操作数相乘,再与第三个操作数求模。 |
0x0A | EXP | 10+50×expBytes | 10+50×expBytes | 求两个操作数的乘方。 |
0x0B | SIGNEXTEND | 2 | 5 | 符号扩展。 |
0x10 | LT | 2 | 3 | 小于比较。 |
0x11 | GT | 2 | 3 | 大于比较。 |
0x12 | SLT | 2 | 3 | 带符号的小于比较。 |
0x13 | SGT | 2 | 3 | 带符号的大于比较。 |
0x14 | EQ | 2 | 3 | 比较是否相等。 |
0x15 | ISZERO | 1 | 3 | 判断是否为 0。 |
0x16 | AND | 2 | 3 | 按位与操作。 |
0x17 | OR | 2 | 3 | 按位或操作。 |
0x18 | XOR | 2 | 3 | 按位异或操作。 |
0x19 | NOT | 2 | 3 | 按位非操作。 |
0x1A | BYTE | 2 | 3 | 取第二个操作数中的某一个字节。 |
0x1B | SHL | 2 | 3 | 左移。 |
0x1C | SHR | 2 | 3 | 逻辑右移。 |
0x1D | SAR | 3 | 3 | 算术右移。 |
0x21 | BLAKE2B | 20+words | 30+6×words | 计算 Blake2b 哈希。 |
0x30 | ADDRESS | 1 | 2 | 获取当前账户地址。 |
0x31 | BALANCE | 150 | 400 | 获取当前账户某种代币的余额。 |
0x33 | CALLER | 1 | 2 | 获取直接调用者地址。 |
0x34 | CALLVALUE | 1 | 2 | 获取调用交易中的转账金额。 |
0x35 | CALLDATALOAD | 2 | 3 | 获取本次调用的参数数据。 |
0x36 | CALLDATASIZE | 1 | 2 | 获取本次调用的参数数据大小。 |
0x37 | CALLDATACOPY | memGas + 3 + 3×memWords | memGas + 3 + 3×memWords | 将调用参数数据拷贝到内存。 |
0x38 | CODESIZE | 1 | 2 | 获取在当前环境中运行的代码的大小。 |
0x39 | CODECOPY | memGas + 3 + 3×memWords | memGas + 3 + 3×memWords | 将当前环境中运行的代码拷贝到内存。 |
0x3D | RETURNDATASIZE | 1 | 2 | 获取前一次调用返回的数据大小。 |
0x3E | RETURNDATACOPY | memGas + 3 + 3×memWords | memGas + 3 + 3×memWords | 将前一次调用返回的数据拷贝到内存。 |
0x42 | TIMESTAMP | 1 | 2 | 获取最新快照块的时间戳。 |
0x43 | HEIGHT | 1 | 2 | 获取最新快照块的高度。 |
0x46 | TOKENID | 1 | 2 | 获取交易的转账代币 id。 |
0x47 | ACCOUNTHEIGHT | 1 | 2 | 获取账户链高度。 |
0x48 | PREVHASH | 1 | 2 | 获取账户链上一个块的哈希。 |
0x49 | FROMHASH | 1 | 2 | 获取请求交易的哈希。 |
0x4A | SEED | 200 | 2 | 获取随机数种子。 |
0x4B | RANDOM | 250 | 2 | 获取一个新的随机数。 |
0x50 | POP | 1 | 2 | 从栈顶弹出一条数据。 |
0x51 | MLOAD | 2 | 3 | 从内存加载一个字。 |
0x52 | MSTORE | memGas + 1 | 3 | 保存一个字到内存。 |
0x53 | MSTORE8 | memGas + 1 | 3 | 保存一个字节到内存。 |
0x54 | SLOAD | 150 | 200 | 从存储中加载一个字。 |
0x55 | SSTORE | init/reset: 15000, clear: 0, noop: 200, mem: 200 | 5000 | 保存一个字到存储。 |
0x56 | JUMP | 4 | 8 | 跳转指令。 |
0x57 | JUMPI | 4 | 10 | 条件跳转指令。 |
0x58 | PC | 1 | 2 | 获取程序计数器的值。 |
0x59 | MSIZE | 1 | 2 | 获取内存大小。 |
0x5B | JUMPDEST | 1 | 1 | 标注一个跳转目的地。 |
0x60~0x7F | PUSH | 1 | 3 | 压栈操作。 |
0x80~0x8F | DUP | 1 | 3 | 复制操作。 |
0x90~0x9F | SWAP | 2 | 3 | 交换操作。 |
0xA0~0xA4 | LOG | 375 + 375×topics + 8×dataBytes | 375 | 扩展日志记录。 |
0xF1 | CALL | 7500 | 11000 | 调用另一个合约。 |
0xF3 | RETURN | 0 | 0 | 停止执行并返回数据。 |
0xFD | REVERT | 0 | 0 | 停止执行,恢复状态并返回数据。 |
- | memGas | words + words×words/1024 | 3×words + words×words/512 | 内存扩展。 |
- | confirmTime | 40 | 200 | 创建合约时指定了 confirmTime 的合约,合约链上的每笔响应交易对 confirmTime 收取配额。 |
- | code | 160 | 200 | 创建合约响应交易中保存 1byte 代码。 |