Rand Protocol
文档
核心概念

费用

一笔交易以 RAND 向链支付什么:每类操作的固定下限、调用在 chain 21 上支付的 gas 价格与字节价格、费用的去向以及 chain 21 销毁的部分、为何此处的 gas 是一种价格而非对执行的限制,以及发送方改用自己的机器时支付什么。

使用本页可以为交易设定费用、估算部署或调用的成本,并了解验证者(validator)获得的报酬。费用均以 RAND 计,且为下限。除调用外,每种操作都支付固定费用。自 chain 18 起,调用按其证明所声明的 gas 上限和字节数付费,价格随区块的充盈程度浮动,并自 chain 20 起设有价格上限。在 chain 21(fullnode v0.8.0,自 2026-10-12 起上线)上,下限本身被销毁,提议者只保留小费(见下文)。

费用下限

费用以 10⁻⁹ RAND 为单位。常量位于 randprotocol_core::gas:

交易下限当前
任意 bundle:RAND 或任意 RPL 代币的转账、质押(bond)、桥接存入(BridgeAttest,由其中继者支付)、TokenMint、SetAuthority、TokenBurn、ListBackingBUNDLE_BASE = 1,000,000 单位0.001 RAND
DeployBUNDLE_BASE + DEPLOY_PER_WORD(100,000)×(程序字数 + 公开字数)256 字的程序:0.0266 RAND;4,096 字的程序:0.4106 RAND;65,096 字的 SPL Token 镜像及其 27,151 字的公开输入:9.2257 RAND(2026-09-19 部署于 chain 13)。自 chain 16 起(hardening_v6,含 chain 21),任何调用都无法承载的部署会被拒绝,错误为 ProgramUncallable:无公开输入的程序超过 8,180 字,有公开输入的则更少。该镜像在 chain 21 上会被拒绝
Call在创世配置含 gas 段的链上(chain 21,与 chain 18 至 20 相同):BUNDLE_BASE + gas_price × 调用证明所声明的 gas 上限 + byte_price × 调用证明与输入信封的每 KiB(不足 1 KiB 按 1 KiB 计),从第 0 字节起计。见 chain 18 上的 gas。在没有该段的链上:BUNDLE_BASE + call_fee(tier),其中 call_fee = CALL_BASE(1,000,000)+ 10 以上每两个层级 100,000,再加调用证明与输入信封超出 2,097,152 + 18,432 字节免费额度的部分每 KiB(不足 1 KiB 按 1 KiB 计)1,000 单位chain 21,按 100 与 800 单位的起始价格(与 chain 20 相同):声明了该层级上限 20,479 gas、证明与信封共 1,350,000 字节的 tier 14 调用,下限为 0.0041 RAND;钱包的默认值支付更多(见下文)。无 gas 段时,如 chain 15:tier 10:0.002;tier 14:0.0022 RAND,在免费额度之内。自 v0.5.6 起,高于 tier 14 的调用无论支付多少都会被拒绝(MAX_CALL_TIER)。2026-09-19 在 chain 13 上发出的 ERC-20 approve 调用(tier 16,证明为 3,412,405 字节)支付了 0.00357 RAND,自 v0.5.6 起在任何链上都会被拒绝
Invoke(RPL-2,自 chain 20 起)一次调用的下限,加上创世配置 program_state.cell_fee 乘以该状态转移所创建的每个单元(cell,即原先无存储、被写入非零值的单元);改写或删除单元不增加费用chain 21 上的 cell_fee 为 0.01 RAND,与 chain 20 相同:上文的 tier 14 调用创建两个单元,下限为 0.0241 RAND
BridgeBurnBRIDGE_BURN_FEE = 10 × BUNDLE_BASE:基础费用加上桥自身的收费,两者均从销毁交易携带的那一个 bundle 中支付0.01 RAND;自 chain 20 起,桥还会保留所销毁 zUSD 的 10 bps(见下文)
RegisterToken、RegisterBridgedTokenBUNDLE_BASE + 代币注册表的 registration_fee(创世参数)chain 21,与 chain 20 相同:0.001 + 1 RAND = 1.001 RAND,其中 1 RAND 被销毁
Mint(水龙头)、Unbond0;无 bundle,由验证者签名—
PauseMints、UnpauseMints0;无 bundle,由暂停密钥或 PQ 守护者法定人数授权,因此不持有 RAND 的钱包也能执行暂停—
Withdraw链上为 0;0.001 RAND 的基础费用从提取金额中扣除提取 1,000 RAND 会生成价值 999.999 的票据

费用是 bundle 的一个公开字,且始终以 RAND 计。隐藏资产 bundle guest 将其绑定到 RAND 组的余额关系 in₂ + in₃ = out₂ + out₃ + fee + burn_r(槽位 2–3)中,因此费用从隐藏票据中支付,而不泄露是哪几张;代币则在同一 bundle 的槽位 0–1 中按其自身的关系 in₀ + in₁ = out₀ + out₁ + burn_a 流转。因此,一份证明即可转移代币并支付其 RAND 费用,持有代币但没有可花费 RAND 的钱包会在生成证明之前就被拒绝。

桥的收费落在销毁交易上,因为这是唯一一种发送者必然持有 RAND 的桥交易;存入只支付基础费用,因为存入者此时尚无 RAND。注册费是账本中的事实,而不属于 fee_floor 的一部分,因此按该操作自身的规则检查(RegistrationFeeTooLow),就像调用的 gas 或层级部分在其证明解码后才计费一样。调用的下限会被检查两次,因为它所声明的内容只有在证明通过验证后才可信。在按 gas 计量的链上(chain 21,与 chain 18 至 20 相同),第一次检查在任何验证之前进行,按调用的字节数和声明上限 1 计价(Invoke 在此还需支付其单元费用);第二次检查则按已验证证明所声明的上限计价。在没有 gas 段的链上,这两次分别是 BUNDLE_BASE + CALL_BASE 和按层级精确计算的下限。

不要猜测,直接询问节点:

rand fee bundle          # 0.001 RAND
rand fee deploy 256      # 0.0266 RAND
rand fee call 14 --gas 20479 --bytes 1350000   # 0.0041 RAND at chain 21's starting prices (chain 20's)
→ {"method":"rand_estimateFee","params":[{"kind":"call","tier":14,"gas":20479,"bytes":1350000}]}
← "4103100"

该答案即起始价格下的 1,000,000 + 100 × 20,479 + 800 × 1,319;节点在被询问时,按区块链顶端当时的价格计价。自 chain 20 起,通过 JSON-RPC 调用时调用规格的 gas 字段为必填(缺失则返回 -32602)。不带 --gas 的 rand fee call <tier> 发送该层级的上限,不带 --bytes 则不对任何字节计价。invoke 的计价方式相同,使用 "kind":"invoke" 与 "created_cells": c,增加 c 份单元费用(上例创建两个单元时为 24103100,2026-10-01 向 chain 20 查询所得)。在没有 gas 段的 chain 15 上,rand fee call 14 的答案是 0.0022 RAND。

钱包的默认值恰好等于下限,唯独按 gas 计量的链(chain 21)上的调用除外,其默认值会增加余量(见下文);rand send --fee <RAND>,以及 bond、call、bridge-mint、bridge-burn(默认 0.01)和 token 子命令上的 --fee 标志可以提高费用。高于下限的部分即为小费。

chain 18 上的 gas

chain 18 自 2026-09-29 上线至 2026-10-01,是第一条按 gas 计量的链;chain 19 是它在同一构建上的重新创世,携带相同的 gas 段。chain 20(v0.6.8)保留了本节的全部规则,并增加了两个价格上限,以及仅对实际付费字节计数的字节负载(见下文)。chain 21(v0.8.0,2026-10-12)沿用 chain 20 的 gas 段,只是区块的字节目标随其更小的区块上限而调整。没有 gas 段的链仍沿用上表中的层级费用表。

计什么。 一个 gas 即 zkVM 的 cpu 表中的一行,因此一条普通指令的成本为 1。系统调用是仅有的其他成本:

操作gas
任意指令、HALT、WRITE_OUTPUT、READ_INPUT、READ_PUBLIC1
对 n 个字的 POSEIDON23 + 3 × ⌈n/4⌉(每个吸收行成本为 3)
SHA256,一次压缩64
KECCAK,一次置换192

声明的上限。 调用证明比以前多携带一个公开值 GAS_LIMIT,电路(约束集 8)证明本次运行的 gas 不超过它。确切的 gas 仍保持私密。高于证明自身头部所设上限的声明值,会在构建任何验证者密钥之前就被拒绝:

gas_max = (2ᵗ − 1) + 2^(t−2) + 191 × (keccak rows / 32) + 63 × (sha256 rows / 64)

对于不使用任何哈希表的调用,tier 10 为 1,279,tier 12 为 5,119,tier 14 为 20,479。

下限。 账本按区块开始时生效的价格,对声明的上限和字节数收费:

fee ≥ BUNDLE_BASE + gas_price × gas_limit + byte_price × ⌈bytes / 1024⌉

bytes 为调用证明加上输入信封。层级费用表及其免费额度在这样的链上不适用。交易池的要求与区块完全一致,并将更便宜的调用拒绝为 FeeTooLow。

bundle 与授权证明声明固定的上限。 每个 bundle 证明都必须恰好声明创世配置的 bundle_gas_limit,即 20,479(tier 14 的上限),否则交易会被拒绝为 BundleGasLimit。chain 21 与自 chain 17 以来的每条链一样,运行拆分授权,因此每个 bundle 都携带一份 tier 10 的授权证明,其必须声明 1,279(AuthGasLimit);由私有多签策略授权的 bundle(chain 21 新增)则携带第二个 auth guest 的 tier 18 证明(交易)。两者都不是额外收费:转账、质押或部署仍然支付上表中的固定下限。钱包会自行声明这两个值。

价格会变动。 自 chain 18 起,gas 部分带有 dynamic 控制器,因此 gas_price 和 byte_price 属于账本状态,并提交在状态根中。每个区块在其交易之后,每个价格按该区块相对目标的充盈程度调整一次:

price' = min(max_price, max(min_price, price + ⌊price × adjust_bps × (used − target) / (10,000 × target)⌋))

used 的上限为目标的两倍,因此 adjust_bps 是单个区块在任一方向上所能做出的最大调整幅度。max_price 是创世时设定的上限;chain 18 和 19 没有上限。byte_price 跟随区块的付费字节数(见下文);gas_price 跟随其中各 call 与 invoke 所声明限额之和,外加每个 bundle 的 20,479。

chain 21 的 gas 部分(与 chain 20 相同,仅字节目标不同)值
创世时的 gas_price、byte_price每 gas 100 单位;每 KiB 800 单位
min_gas_price、min_byte_price100;800,因此起始价格同时也是下限
max_gas_price、max_byte_price10,000;80,000:上限,为下限的 100 倍(chain 20 新增)
byte_loadpaying(chain 20 新增)
target_block_byteschain 21 上为 9,961,472,即 19 MiB 区块上限的一半(chain 20 上为 10,485,760,即 20 MiB 的一半)
target_block_gas262,144
adjust_bps1,250:每个区块最多 12.5%
bundle_gas_limit20,479
meteringcircuit

低于目标的区块会使价格下降,因此在空闲的链上价格停在下限。rand_getLimits 返回链端当前的 gas_price 和 byte_price,以及 gas_metering: "circuit"、bundle_gas_limit、adjust_bps,自 v0.6.8 起还包括 max_gas_price、max_byte_price 和 byte_load(在没有这些字段的链上为 null);rand_status 以 gas_prices 报告同样的两个价格。

价格上限与付费字节负载

两者都是 gas.dynamic 的创世字段,在 v0.6.8 中新增(审计 v6,POOL-2),chain 20 是第一条设置它们的链。它们修复了 chain 18 和 19 存在的一个缺陷。在那两条链上,byte_price 随每笔交易的编码长度变动,而只有 call 才支付该价格。七笔转账(每笔约 2.85 MB,固定费用)即可将区块填至字节目标的约 1.9 倍,使价格每个区块上涨约 11%,且没有上限:约 65 个这样的区块就会把价格推高到起始值的 1,000 倍,此时一次 call 的费用约为 1 RAND,而不是约 0.004。

  • 上限。 max_gas_price 和 max_byte_price 是控制器永不越过的价格。调整步长不变,随后再做截断(gas::next_price_capped),因此处于上限的价格在任意连续的满区块中都保持不变,并在第一个低于目标的区块上回落。创世配置必须将每个上限设置为不低于其起始价格。在这些上限下(chain 21 沿用 chain 20 的上限),上文的 tier-14 call(20,479 gas 和 1,319 KiB)的下限为 0.3113 RAND,这是其下限所能达到的最高值。
  • 付费字节负载。 在 byte_load: "paying" 下,区块的 bytes_used 只统计按字节价格收费的字节:每个 Call 和 Invoke 的证明加输入信封(gas::call_bytes),转账、质押或销毁不计入。一个全是转账的区块不会推动字节价格。Ledger::block_usage 同时为提议者和副本计算该数值,因此两者一致。

在付费负载下,一个全是转账的区块不会给 call 提供任何价格信号,因此诚实的提议者还会为 call 预留空间。这是节点策略,而非有效性规则:当有 call 或 invoke 在池中且支付了其当前下限时,固定费用交易在第一轮中至多占用区块字节的四分之三,最后四分之一中 call 未用完的部分再由先前被搁置的转账填满(Mempool)。

钱包为 call 支付什么

rand call 先在模拟器中运行程序,并打印 gas: <exact> (declaring <limit>, tier <t>)。默认情况下,它声明将精确 gas 向上取整到 2^(tier − 2) 的倍数;--gas-limit N 声明一个精确数值,--gas-limit max 声明区块头的上限。

有两个因素使默认费用高于下限:

  • 证明按上限定价。 自 chain 16(hardening_v6,包括 chain 21)起,call 证明与其所属交易绑定,因此费用在证明生成之前就已确定。钱包以链的证明上限(chain 21 上为 6 MiB,chain 18 至 20 上为 4 MiB)代替真实的证明大小来定价(wallet::hardened_call_quote_bytes)。这只会多付,不会少付。
  • 两个价格步长的余量。 rand_getLimits 返回已提交的链头价格,而 call 会在两到三个区块之后上链,因此默认值将下限乘以 (1 + adjust_bps / 10,000)²,在 chain 21 上即 1.125²,与 chain 20 相同。

2026-09-30 在 chain 18 上的实测显示,四次 call 在这些默认值下每次花费 0.0057 至 0.0075 RAND(Example programs)。--fee 可覆盖默认值;钱包在提交前会按真实证明重新定价,并拒绝低于下限的费用。

费用的去向

在 chain 21 上,下限被销毁,提议者保留小费。 chain 21 的创世配置带有一个 fees 部分,其中设置了 burn_base 和 burn_floor(fullnode v0.8.0;rand_getLimits.fee_rules 将其返回为 {"burn_base": true, "burn_floor": true, "subsidy_net_of_fees": false, "proposer_share_bps": null, "prove_base": null, "usd_subsidy": null})。在每个 bundle 的费用拆分中,账本针对该 bundle 自身的下限——转账、质押、代币操作或证明声明为 BUNDLE_BASE;Deploy 为 BUNDLE_BASE 加上按字计的部分;Call 为按区块价格计算的、精确到 tier 的 call 下限,Invoke 还要加上 cell 费用;BridgeBurn 为 BRIDGE_BURN_FEE,因此桥自身的费用与基础费用一并被销毁——全部被销毁(burned = min(fee, floor)),而验证者登记册中的区块提议者的 rewards(这是本链上唯一以明文存储金额的地方)仅增加小费,即 fee − floor。rand_getSupply 在 base_fees_burned 中统计被销毁的部分,它位于供应恒等式的右侧,与 registration_fees_burned 并列(Supply),而 fees_paid 按提议者保留的数额变动。发送方的支付不变:下限和钱包的默认值就是上文的数字,不同的只是下限的去向。之所以选择忠实的 EIP-1559 形式,而不是只销毁基础费用,是为了让提议者不会从抬高价格的区块中获益。登记的 registration_fee 不属于下限;它按自己的标志照常销毁。

在 chain 15 至 20 上,全部费用(下限与小费)都计入提议者,但有一个例外。在设置了 tokens.burn_registration_fee 的创世配置上(chain 21 即如此,自 chain 15 起的每条链亦然),RegisterToken 或 RegisterBridgedToken 的 registration_fee 会被销毁,提议者保留 fee − registration_fee;rand_getSupply 在 registration_fees_burned 中统计它。在缺少该标志的 chain 14 上,提议者保留全部费用。验证者通过 rand-node withdraw 将累积的奖励转为 note(Staking)。chain 21 上没有区块奖励,也没有通胀:小费就是验证者的全部收入。Withdraw 的基础费用在登记册一侧从提取金额中支付,不经过 bundle 的费用拆分,因此不会被销毁。

自 chain 20 起有一项费用不是 RAND,也不流向任何验证者。依据创世配置的 bridge.fees(v0.6.8 新增,沿用至 chain 21),桥对每笔 zUSD 存入和每笔 zUSD 销毁收取 10 bps,向下取整到抵押资产的整数赎回单位,并以 zUSD note 的形式支付到创世配置指定的金库地址。存入方获得扣除费用后的金额;销毁则在源链上释放 amount − fee。该费用 note 仍保持已发行且有抵押。参见 Bridge 和 RPL tokens。

内存池按每 KiB 超出下限的支付额对候选交易排序,其次按费用排序(Mempool),因此更高的费用只在拥堵时才有意义。一笔转账约为 2.85 MB(在 chain 18 上测得):1.49 MB 的 bundle 证明加上 1.36 MB 的授权证明,因此按此大小,chain 20 的 20 MiB 区块约容纳七笔,chain 21 的 19 MiB 区块约容纳六笔(chain 21 上约束集 9 的证明大小此处尚未测量)。fullnode 自身的说明是,在主网之前,下限应当演变为针对字节而非操作码的费用市场。自 chain 20 起,字节价格就是针对 call 的这一市场,仅随 call 所支付的字节变动;转账的下限仍是固定的,自 chain 21 起它被销毁。

为什么这里的 gas 是价格,而不是上界

Ethereum 对每个操作码计量,因为每个节点都要执行每笔交易,而执行是没有边界的。在 Rand 上,没有节点执行任何东西:发送方在链下运行一次程序,然后把证明交给链。节点对每笔交易的工作是一个固定的序列——解码公开字段、运行免费检查、验证一个 STARK——无论程序做了什么,在验证者密钥已预热的情况下,这一验证约需 16 ms。因此 gas 的三项职责就此分离:

  • 终止性由层级(tier)强制保证:在 2ᵗ − 1 个周期内无法停机的运行根本无法被证明,由 prover 自行承担这一失败。
  • 为工作量定价是 gas 下限自链 18 起所做的事。网络对每条指令的成本接近于零,但发送方的证明工作是实打实的,而固定的下限把一次百万周期的调用与一次千周期的调用定成同样的价格。在链 18 之前,下限按层级固定。
  • 区块大小由字节预算(默认 MAX_BLOCK_BYTES = 4 MiB,否则取创世块的 max_block_bytes)和交易数量(2,000)共同限定。

fullnode 明确指出了两点注意事项:字节数确实会变化(一个证明超过 1 兆字节,因此稀缺资源是区块空间,而非计算),而状态增长——树、nullifier 集合、已部署的程序字节——仅由按字计的部署费用和固定的基础费用定价,这对 testnet 已足够,在状态规模变得重要时值得重新审视。

发送方转而支付的成本:证明

唯一会变化的成本是生成 STARK 证明,且只有发送方的机器承担。按影响大小排序:

  1. 层级 t ∈ {10, 12, 14, 16, 18, 20}(自 v0.5.6 起,链上拒绝高于 14 的调用;bundle 固定为 14,自链 17 起其旁还附带一个层级 10 的授权证明,约多出 7 秒):cpu 表被填充至 2ᵗ 行,每上升一级,填充后的轨迹大约增至四倍。在开发笔记本上的实测:层级 10 的 private_payment 约需 7 秒;隐藏资产 bundle 的 guest 在层级 14 约需 100 秒,无论它转移的是哪种资产。
  2. 执行的周期数,因为它决定层级:计的是运行的指令,而不是写下的指令。
  3. 程序大小,影响较小:轨迹开头每四个字对应一行摘要。
  4. 私有输入大小,同样如此。
  5. 存在哪些表:只有当 guest 用到 keccak 或 sha256 表时,才会计入其各列所占的份额。
  6. FRI 配置:用 80 次查询代替 27 次会使证明大小变为三倍,但几乎不改变证明时间。

证明不取决于金额、发送方持有多少 note,也不取决于链的规模:成员资格是针对固定深度的树来证明的,因此一笔转账在第十个区块和第一千万个区块的成本相同。

参考

constantvalue
BUNDLE_BASE1,000,000 units
BRIDGE_BURN_FEE10,000,000 units (10 × BUNDLE_BASE)
registration_fee (genesis tokens section)链 21 上为 1,000,000,000 units,与链 20 相同,被销毁(burn_registration_fee)
DEPLOY_PER_WORD100,000 units
CALL_BASE, CALL_PER_TIER_STEP1,000,000; 100,000 units; 未设置 gas 部分的链所采用的层级价目表
GAS_PRICE_DEFAULT, BYTE_PRICE_DEFAULT每 gas 100 units;每 KiB 800 units。链 21 的起始价格及其价格下限,与链 20 相同
KECCAK_GAS, SHA256_GAS, POSEIDON2_ABSORB_GAS192; 64; 每行 3 gas
max_gas_price, max_byte_price (genesis gas.dynamic)链 20 和链 21 上为每 gas 10,000 units;每 KiB 80,000 units;缺省时无上限(链 18 和链 19)
byte_load (genesis gas.dynamic)链 20 和链 21 上为 paying:只有 call 和 invoke 的证明及信封字节会推动 byte_price;缺省时为每笔交易的字节
cell_fee (genesis program_state)链 20 和链 21 上每创建一个 cell 为 10,000,000 units(0.01 RAND);最多 1,000 RAND
bundle_gas_limit (genesis gas section)链 21 上为 20,479,自链 18 起如此,即 gas_max(14, 0, 0);一个授权证明声明为 1,279,即 gas_max(10, 0, 0)
adjust_bps (genesis gas.dynamic)链 21 上为 1,250,自链 18 起如此;创世块可设为 1 至 5,000
target_block_bytes, target_block_gas (genesis gas.dynamic)链 21 上为 9,961,472 字节(链 20 上为 10,485,760);262,144 gas
fees section (genesis, chain 21)burn_base 和 burn_floor 为 true:每个 bundle 结算后的下限都被销毁,并计入 rand_getSupply.base_fees_burned;提议者保留 fee − floor。subsidy_net_of_fees、proposer_share_bps、prove_base 和 usd_subsidy 未设置:它们涉及聚合型链,而链 21 没有 aggregation 部分
MAX_PROGRAM_WORDS4,096,除非创世块设置了 max_program_words(至多 65,535;链 20 和链 21 设为 65,535,且 hardening_v6 拒绝任何超过 8,180 个字、没有调用能容纳的程序)
MAX_PROOF_BYTES2 MiB,除非创世块设置了 max_proof_bytes(链 21 上为 6 MiB,为层级 18 的 private-multisig 授权证明留出空间;链 18 至 20 上为 4 MiB;链 13 至 15 上为 8 MiB)
MAX_BLOCK_BYTES, MAX_BLOCK_TXS4 MiB(除非创世块设置了 max_block_bytes;链 21 上为 19 MiB,链 20 上为 20 MiB),2,000
tiers10, 12, 14, 16, 18, 20; cycles ≤ 2ᵗ − 1
MAX_CALL_TIER14: 高于此层级的 call 证明在准入时及区块中均被拒绝(自 v0.5.6 起)

最近一次核对所依据的 fullnode 提交为 c0878c3f(链 21),日期为 2026-10-12。 若代码与本页不一致,以代码为准;请告知我们。