Jason @0xbbbb_eth
Account Abstraction Developer
MEV Researcher
Core Contributor of Panta Rhei
StarkNet 交易处理流程
Starknet 交易处理流程如下

用户向序列器(Sequencer)发送交易
序列器处理交易
序列器把交易打包为 L2 区块
交易验证成功(无需执行成功),序列器向用户收取手续费
序列器执行交易并产生执行路径(Trace),并把执行路径提供给证明器(Prover)。
证明器基于执行路径产生相应的有效性证明,并把有效性证明提供给 L1 的 Starknet Verifier 合约进行验证。经过验证后的有效性证明被注册为 fact。
证明器支付 L1 手续费
序列器把最新 L2 状态根提供给 L1 的 Starknet Core 合约。Starknet Core 合约查询相应的 fact 是否被注册。若已注册,Starknet Core 合约更新其存储的 L2 状态根。
序列器支付 L1 手续费
StarkNet 费用机制
竞价模型
费用代币
StarkNet 类似于其他 Layer 2 支持使用 ETH 作为费用代币。特别地,StarkNet 额外支持 STARK 作为其费用代币,赋能 STARK。
由于同时支持 ETH 或 STARK 作为费用代币,对于序列器而言,不得不引入 STARK <> ETH 的汇率 Oracle:
保证收取的 STARK 足以支持 L1 的手续费
保证交易费用可以在同一维度上比较
StarkNet 引入了 Pragma 和 Switchboard 作为 STARK <> ETH 的汇率 Oracle,并预留了 Fallback 逻辑(人工设置汇率)的设计。
然而,引入 STARK 作为费用代币,主要存在以下问题
对于 Layer 2 而言,序列器需要一直卖出 STARK 为 ETH 支付 L1 手续费。对于 STARK 而言,是持久的抛压,不利于 STARK 价格。
Oracle 的价格无法做到实时更新,存在序列器被套利/攻击的风险。
值得注意的是,费用代币指的是 StarkNet 序列器可以直接收取的代币。
对用户而言,在后续引入 Paymaster 后,用户实际上可以通过 Paymaster 使用其他代币(如 USDC, USDT, …)支付手续费。
User → Paymaster:
3500 USDC
Paymaster → Sequencer:
1 ETH
/6000 STARK
更多关于“用原生 L2 代币支付手续费”的讨论:
交易优先级
类似于大部份的 Layer 2,StarkNet 交易依据“先到先得”的原则进行处理。
在该原则下,手续费高的交易在网络拥堵的情况下无法得到优先处理。
另外,套利者需要花费大量的成本用于提升网速以捕获套利利润,而这部分成本本可以由序列器所捕获。
费用限额
目前,StarkNet 交易的限额主要从两个维度定义
`max_fee` 定义交易的费用上限,单位为 FRI (1 FRI = 10^-18 STARK)
`resouce_bounds` 定义限制交易中资源的使用,目前只支持资源 `l1_gas`
`max_amount`: 资源使用上限
`max_price_per_unit`: 资源单价上限,单位为 FRI
费用模型
StarkNet 费用模型考虑如下维度
验证费用
证明器会为聚合多笔交易为一个批次生成一个有效性证明。有效性证明需要提交给 L1 的 Starknet Verifier 合约进行验证,该过程需要支付 L1 手续费。验证费用即交易需要在该批次分摊的 L1 手续费。验证费用可以表示为 `验证 Gas Price` 和 `验证 Gas` 的乘积。
验证 Gas Price
验证 Gas Price 很直观,即 L1 的 Gas Price。然而,序列器收取用户手续费和有效性证明上链发生在不同的时间点,两个时间点的 L1 Gas Price 是不同的。因此,StarkNet 使用的 `L1_Gas_Price` 经过如下处理:
Starknet 每分钟采样 L1 的 Base Fee
`L1_Gas_Price` ← 最近的 60 个样本的平均数 + 1 gwei
验证 Gas
验证 Gas 即交易需要在批次验证中分摊的 Gas,分摊比例为交易消耗的资源与批次消耗资源的比例。
假设证明器的处理上限是为 500,000,00 个 Cairo Step 生成证明,而交易消耗了 58,041 个 Cairo Step。
交易的分摊比例为 58,041 / 500,000,00
批次验证消耗的 L1 Gas 为验证含 500,000,00 个 Cairo Step 的 Proof 所需的 L1 Gas
然而,交易的执行证明不单单消耗某种资源(Cairo Steps),实际上需要消耗多种资源 (Cairo Steps, Pedersen hashes, range checks, …)。
那么,在多种资源的场景下,StarkNet 如何计算交易的验证 Gas ?
StarkNet 的基本理念为基于瓶颈资源计算交易的验证 Gas。
基于上述理念推到下面例子中交易的验证 Gas
RANGE_CHECK 为交易瓶颈资源,证明者的 RANGE_CHECK 资源的消耗比例最大
STEPS → 58041 / 500,000,000
PEDERSEN → 98 / 20,000,000
EC_OP → 3 / 4,000,000
RANGE_CHECK → 3299 / 10,000,000 (MAX)
交易的分摊比例为 3299 / 10,000,000(RANGE_CHECK 的分摊比例)
批次验证消耗的 L1 Gas 为验证含 10,000,00 个 Range Check 的 Proof 所需的 L1 Gas
综上,我们可以得到 StarkNet 交易的验证 Gas 的计算方式
CairoResourceFeeWeight 由 StarkNet 协议所定义,表征单个资源在有效性证明中 Gas 消耗。
数据可用费用
StarkNet 作为 Layer 2 需要向 Layer 1 提交可用性数据,该过程需要支付 L1 手续费。数据可用费用即交易需要分摊可用性数据交易的 L1 手续费。数据可用费用可以表示为 `数据可用 Gas Price` 和 `数据可用 Gas` 的乘积。
数据可用 Gas Price
EIP-4844 后,StarkNet 选择 Blob 承载其可用性数据。因此,数据可用 Gas Price 很直观,即 L1 的 Data Gas Price。类似地,序列器收取用户手续费和可用性数据上链发生在不同的时间点,两个时间点的 L1 Data Gas Price 是不同的。因此,StarkNet 使用的 `L1_Data_Gas_Price` 经过如下处理:
Starknet 每分钟采样 L1 的 Data Base Fee
`L1_Gas_Price` ← 最近的 60 个样本的平均数
数据可用 Gas
StarkNet 中交易的可用性数据并非交易本身,而是交易执行后状态的更动(State Diff)。State Diff 是 ZkRollup 区别于 Optimistic Rollup 的可用性数据形式,可用性数据量较小。
数据可用 Gas 可以表示如下
对于 Blob 而言,1 Data Gas 对应 1 字节的可用性数据
StarkNet 中的数据单元为 felt 而非 byte
因此,`felt_size_in_bytes` 为单个 felt 消耗的 Data Gas
下面分析交易的 State Diff 需要消耗多少的 felt
合约状态更新 → 2(n-1)
n → n 个合约状态更新
n-1 → 由于每笔交易 Fee Token 合约的状态都会更新,因此不考虑 Fee Token 合约
2(n-1) → 每个合约状态更新对应 2 felt 的可用性数据
合约地址
合约元数据(见下图)
键值对更新 → 2(m-1)
m → m 个键值对更新
m-1 → 由于每笔交易 Sequencer 的余额都会更新,因此不考虑该键值对的更新
2(m-1) → 每个键值对更新对应 2 felt 的可用性数据
键
值
合约的 Class 更新 → l
l → l 个合约 Class 更新,来自于
合约部署
replace_class 系统调用
合约 Declare → 2D
D → D 个合约 Declare
2D → 每个合约 Declare 对应 2 felt 的可用性数据
Class 哈希
Complied Class 哈希(节省重新编译计算 Compiled Class 哈希的成本)
值得注意的是,StateDiff 只考虑交易执行前后的状态变更,不考虑中间状态。
L2 Payload 费用
L2 Payload 指的是存储到 Layer 2 的数据,包括
calldata
events
ABI
CASM bytecode
Sierra bytecode
L2 Payload 虽然无需提交至 Layer 1,但仍然是有存储成本的(虽然远低于 L1 的存储成本)。因此,用户需要支付 L2 Payload 的费用。
L2 Payload Gas Price
L2 Payload Gas Price 跟验证 Gas Price 相同,为 L1_Gas_Price。理论上,L2 Payload 与 L1 没有直接关系,因此无需使用 L1_Gas_Price,跟 L1 耦合起来。笔者推测是为了简化计算,免得额外引入 L2_Gas_Price 以及 L2_Gas。
L2 Payload Gas
L2 Payload Gas 由 StarkNet 协议所定义。根据下图,我们可以得知 L2 存储成本远低于 L1。例如,L2 的 Calldata 成本为 0.128 gas/felt,而 L1 的 Calldata 成本为[非零字节 16 gas/byte, 零字节 4 gas/byte]。
L2 → L1 跨链费用
如果 StarkNet 交易涉及跨链 L2 → L1,那么跨链数据需要提交至 Layer 1。因此,用户需要支付相应的成本。
L2 → L1 Gas Price
显然,L2 → L1 Gas Price 跟验证 Gas Price 相同,为 L1_Gas_Price。
L2 → L1 Payload Gas
L2 → L1 Payload 的 Gas 消耗主要分布在三部份
L2 → L1 数据需要作为 calldata 提交至 StarkNet Core 合约和 StarkNet Verifier 合约
StarkNet Core 合约需要存储 L2 → L1 数据的哈希
StarkNet Core 合约需要发起 `LogMessageToL1` 事件
具体的计算方式见此处。
分析:继 EIP-4844 后,Starknet 降费 100 倍
在 EIP-4844 后,文章《继 EIP-4844 后,Starknet 降费 100 倍,但事情没有这么简单》传播得很广。文章作者的结论是
L1DA 费用大降,但解释不了两个数量级的下降
那么唯一合理的解释就是——之前确实「心黑」收太高了。在 STRK 代币发行之前,Starknet 的所有开发,社区激励都需要资金,除了烧投资人的钱之外,设置更高的 L2 L1 Gas 差价可能是他们维系开发的方式之一,才造成了此前 Starknet 令人尴尬的 Gas 费局面。
然而,该文章主要分析的是 StarkNet 从使用 calldata 作为数据可用方案切换为 blob 导致的交易成本的降低,而忽略了手续费的其他维度。
从 StarkNet 的 version-notes 可以看到,在 Starknet v0.13.1 的升级中除了适配了 EIP-4844 外,其他费用维度也发生了改变。
最为亮眼的是验证 Gas 成本更新为原来的一半。这背后不是简单的参数调整,而是 StarkNet 技术优化支持`更大的区块`, `SHARP 性能的提升` 以及 `更小的有效性证明`。
展望 StarkNet 费用机制
引入 L2 Gas
在上文的 L2 Payload 中,有一个不协调的地方是 L2 Payload 竟然使用 L1 Gas Price 进行计价。在未来,StarkNet 会把 Gas 分类成 L1 Gas 以及 L2 Gas,有着相应的 L1 Gas Price 和 L2 Gas Price。
引入 L2 Gas 使得费用模型更加合理
发生在 L2 的费用,单独使用 L2 Gas 衡量,使得 L2 自身费用市场成为可能。
发生在 L1 的费用,使用 L1 Gas 衡量。
实际上,StarkNet 已经在为该优化准备,虽然仍未激活,见下图中的 `l2_gas`。
引入交易打包优先级
StarkNet 打算在 v0.14.0 引入交易打包优先级,优化在网络拥堵情况下的交易处理。处理方式如下:
交易可以额外提供 L2 Tip,让序列器优先处理该交易(新)
L2 Gas 有着对应的 L2 Gas Limit & Max L2 Gas Price(新)
L1 Gas 有着对应的 L1 Gas Limit & Max L1 Gas Price
交易有对应的手续费上限 Max Total Payment
引入 Paymaster
StarkNet 未来会引入 Paymaster,支持多种形式的手续费支付
代付手续费
使用各种非 ETH / STARK 的代币支付手续费,如 USDT, USDC, …
目前的 StarkNet 交易已经预留了 `paymaster_data` 字段,但仍未激活
支持 Volition
对于 ZK Rollup 而言,可用性数据会发布到 Layer 1。实际上,可用性数据并非一定要发布到 Layer 1,这种解决方案称为 Validium。Validium 的优势在于发布可用性的成本很低,劣势在于数据可用性依赖于存储主体(可能是个多签委员会)。
Volition 本质上是同时提供 ZK Rollup 和 Validium 这两种服务,它们共享同一个状态根,用户可以自行选择每笔交易的 DA 模式。
具体而言,StarkNet 目前在交易中定义如下字段
支持 STARK Staking
未来,StarkNet 会采用去中心化序列器的方案。STARK 的质押者会通过产生/见证/证明区块的方式守护 StarkNet 网络。
Staker 需要获得激励以补偿其机会成本的损失。具体而言,有两种方案
Staker 收取一定的手续费
Staker 直接获得增发的 STARK 奖励
目前,StarkNet 倾向于第二种方式。原因在于方式一会额外增加用户交易的成本,违背了 StarkNet 希望交易费用保持在成本价以吸引更多用户的原则。
参考资料
https://docs.starknet.io/architecture-and-concepts/network-architecture/transactions/
https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-8.md
https://docs.starknet.io/architecture-and-concepts/network-architecture/fee-mechanism/#l2_calldata
https://medium.com/taipei-ethereum-meetup/introduction-of-starknet-account-abstraction-2c343b561d6e
https://medium.com/@clarksjoan48/fees-on-starknet-noam-nisan-95ac3e450a6d
https://starkscan.co/tx/0x03f7d12beacb4a2c2f2c11ebcbf0f406618a335c6f3a6997d5a5405f62d98237
https://starkscan.co/tx/0x00e52e5cdfd48ae7fb2d094dfcdae30cea2ce474ceb263f3d9edf52ef076baa1
https://community.starknet.io/t/starknet-costs-and-fees/113853
https://community.starknet.io/t/starknet-costs-and-fees/113853
https://www.starknet.io/blog/starknets-game-plan-for-slashing-fees-in-2024/
https://docs.starknet.io/architecture-and-concepts/network-architecture/starknet-state