作者:Faust,极客 Web3
导语:如果用一个关键词来概括 2023 年的 Web3,大多数人或许会本能想到「Layer2 之夏」。虽然应用层创新此起彼伏,但能像 L2 一样经久不衰的长期热点却难得一见。随着 Celestia 成功推广模块化区块链概念,Layer2 和模块化几乎成为了基础设施的代名词,单片链的往日辉煌似乎难以重现。在 Coinbase、Bybit 和 Metamask 相继推出专属的二层网络后,Layer2 大战如火如荼,像极了当初新公链间炮火连天的场面。
在这场由交易所引领的二层网络大战中,BNB Chain 必然不肯甘居人下。早在去年他们就曾上线 zkBNB 测试网,但因为 zkEVM 在性能上还无法满足大规模应用,采用 Optimistic Rollup 方案的 opBNB 成为了实现通用 Layer2 的更优方案。本文旨在对 opBNB 的工作原理与其商业意义进行简要概括,为大家梳理 BSC 公链在模块化区块链时代迈出的重要一步。
BNB Chain 的大区块之路与 Solana、Heco 等由交易所扶持的公链类似,BNB Chain 的公链 BNB Smart Chain (BSC) 链对高性能的追求由来已久。从 2020 年上线初,BSC 链就把每个区块的 gas 容量上限设定在 3000 万,出块间隔稳定在 3 秒。在这样的参数设置下,BSC 实现了 100+ 的 TPS 上限(各种交易杂糅在一起的 TPS)。2021 年 6 月,BSC 的区块 gas 上限提升到了 6000 万,但在当年 7 月一款名为 CryptoBlades 的链游在 BSC 上爆火,引发的日交易笔数一度超过 800 万,导致手续费飙升。事实证明,此时的 BSC 效率瓶颈还是比较明显。
为了解决网络性能问题,BSC 再次将每个区块的 gas 上限上调,此后长时间稳定在 8000 万~8500 万附近。2022 年 9 月,BSC Chain 单个区块的 gas 上限提高到了 1.2 亿,年底时提高到了 1.4 亿,达到 2020 年时的近 5 倍。此前 BSC 曾计划把区块 gas 容量上限提升到 3 亿,或许是考虑到 Validator 节点的负担太重,上述超大区块的提议一直没有实施。
后来的 BNB Chain 似乎将重心放在了模块化 /Layer2 赛道,而没有再执着于 Layer1 的扩容。从去年下半年上线的 zkBNB 到今年年初时的 GreenField,这一意图表现的愈加明显。出于对模块化区块链 /Layer2 的浓厚兴趣,本文作者将以 opBNB 为调研对象,从 opBNB 与以太坊 Layer2 表现出的不同,来为读者简单揭示 Rollup 的性能瓶颈所在。
BSC 的高吞吐量对 opBNB 的 DA 层加成众所周知,Celestia 按照模块化区块链的工作流程,归纳出了 4 个关键组件:
执行层 Execution:执行合约代码、完成状态转换的执行环境;
结算层 Settlement:处理欺诈证明 / 有效性证明,同时处理 L2 与 L1 之间的桥接问题。
共识层 Consensus:对交易的排序达成一致共识。
数据可用性层 Data availability (DA):发布区块链账本相关数据,使得验证者可以下载到这些数据。
其中,DA 层与共识层往往被耦合在一起。比如,乐观 Rollup 的 DA 数据包含了一批 L2 区块中的交易序列,当 L2 全节点获取到 DA 数据时,其实就知道了这批交易中每笔 Tx 的先后次序。(正因如此,以太坊社区对 Rollup 分层时,认为 DA 层和共识层是关联的)
但对于以太坊 Layer2 而言,DA 层(以太坊)的数据吞吐量成为了制约 Rollup 性能的最大瓶颈,因为目前以太坊的数据吞吐量太低,Rollup 不得不尽量压制自己的 TPS,防止以太坊主网无法承载 L2 产生的数据。
同时,低下的数据吞吐量使得 Ethereum 网络内大量交易指令处于待处理状态,这使得 gas 费被拉到了极高水准,进一步抬高了 Layer2 的数据发布成本。最后,很多二层网络不得不采用 Celestia 等以太坊之外的 DA 层,「近水楼台先得月」的opBNB 则直接选用高吞吐量的 BSC 实现 DA,以解决数据发布上的瓶颈问题。
为了方便理解,此处需要介绍一下 Rollup 的 DA 数据发布方式。以 Arbitrum 为例,Layer2 排序器控制的以太坊链上 EOA 地址,会定期往指定的合约发出 Transaction,在这个指令的输入参数 calldata 中,写入打包好的交易数据,并触发相应的链上事件,在合约日志中留下永久记录。
这样一来,Layer2 的交易数据被长期保存在了以太坊区块中,有能力运行 L2 节点的人可以下载相应的记录,解析出对应数据,但以太坊自己的节点并不执行这些 L2 交易。不难看出,L2 只是把交易数据存放到以太坊区块中,产生了存储成本,而执行交易的计算成本被 L2 自己的节点承担了。
上面讲到的就是 Arbitrum 的 DA 实现方式,而 Optimism 则是由排序器控制的 EOA 地址,向另一个指定的 EOA 地址进行 Transfer,在附加的数据中携带 Layer2 的新一批交易数据。至于采用了 OP Stack 的 opBNB,和 Optimism 的 DA 数据发布方式基本一致。
显而易见,DA 层的吞吐量会对单位时间内 Rollup 可发布的数据尺寸大小产生限制,进而限制 TPS。考虑到 EIP1559 后,每个 ETH 区块的 gas 容量稳在 3000 万,merge 后出块时间约为 12 秒,则以太坊每秒处理的 gas 总量最多仅 250 万。
绝大多数时候,容纳 L2 交易数据的 calldata,每个字节消耗的 gas = 16,则以太坊每秒能处理的 calldata 尺寸最多只有 150 KB。而 BSC 平均每秒可处理的 calldata 尺寸最大约 2910 KB,达到了以太坊的 18.6 倍。两者作为 DA 层的差距是显而易见的。
可以概括一下,以太坊每秒最多可承载 150 KB 左右的 L2 交易数据。即便在 EIP 4844 上线后,这个数字也不会有多大改变,只不过降低了 DA 手续费。那么每秒 150KB,大概能包含多少笔交易的数据?
这里需要解释下 Rollup 的数据压缩率。Vitalik 在 2021 年曾过分乐观的估计,乐观 Rollup 可以把交易数据尺寸,压缩至原先的 11%。比如,一笔最基础的 ETH 转账,原本占用 calldata 大小是 112 字节,可以被乐观 Rollup 压缩到 12 字节,ERC-20 转账可以压缩到 16 字节,Uniswap 上的 Swap 交易压缩到 14 字节。按照他的说法,以太坊每秒最多能记录 1 万笔左右的 L2 交易数据(各类型掺杂在一起)。但按照 Optimism 官方在 2022 年披露的数据,实践中的数据压缩率,最高只能达到约 37%,与 Vitalik 的估算差了 3.5 倍。
所以我们不妨给出一个合理的数字,就是目前以太坊即便达到自己的吞吐量极限,所有乐观 Rollup 加起来的 TPS 最大值,也只有 2000 多。换句话说,如果以太坊区块全部空间都用来承载乐观 Rollup 发布的数据,比如被 Arbitrum、Optimism、Base、Boba 等瓜分,这些乐观 Rollup 的 TPS 加起来根本不够 3000,这还是在压缩算法效率最高的情况下。此外,我们还要考虑到 EIP1559 后,每个区块平均承载的 gas 量仅为最大值的 50%,所以上面的数字还应该砍掉一半。EIP4844 上线后,尽管会把发布数据的手续费大幅降低,但以太坊的区块最大尺寸不会有多大变化(变化太多会影响 ETH 主链的安全性),所以上面估算的数值不会有多少进步。
根据 Arbiscan 和 Etherscan 的数据,Arbitrum 某个交易批次包含了 1115 笔交易,在以太坊上消耗了 181 万的 gas。如此推算,如果把 DA 层每个区块都装满,Arbitrum 理论上的 TPS 极限约为 1500,当然考虑到 L1 区块重组问题,Arbitrum 不可能在每个以太坊区块上都发布交易批次,所以上面的数字目前只是纸面上的。
同时,在 EIP 4337 相关的智能钱包被大规模采用后,DA 问题会愈加严重。因为支持 EIP 4337 后,用户验证身份的方式可以自定义,比如上传指纹或虹膜的二进制数据,这会进一步加大常规交易占用的数据尺寸。所以,以太坊低下的数据吞吐量是限制 Rollup 效率的最大瓶颈,这个问题今后很长时间可能都无法妥善解决。
而在 BNB chain 的公链 BSC 身上,平均每秒可处理的 calldata 尺寸最大约 2910 KB,达到了以太坊的 18.6 倍。换言之,只要执行层速度跟的上,BNB Chain 体系内的 Layer2,理论 TPS 上限可以达到 ARB 或 OP 的 18 倍左右。这个数字是以当前 BNB chain 每个区块 gas 容量最大 1.4 亿,出块时间为 3 秒,计算得来的。
也就是说,目前 BNB Chain 体系下的公链,所有 Rollup 加总 TPS 极限,是以太坊的 18.6 倍(就算考虑进 ZKRollup,也是如此)。从这一点也可以理解,为什么那么多 Layer2 项目用以太坊链下的 DA 层来发布数据,因为差异是显而易见的。
但是,问题没有这么简单。除了数据吞吐量问题外,Layer1 本身的稳定性也会对 Layer2 造成影响。比如大多数 Rollup 往往要间隔几分钟才往以太坊上发布一次交易批次,这是考虑到 Layer1 区块有重组的可能性。如果 L1 区块重组,会波及到 L2 的区块链账本。所以,排序器每发布一个 L2 交易批次后,会再等多个 L1 新区块发布完,区块回滚概率大幅下降后,才发布下一个 L2 交易批次。这其实会推迟 L2 区块被最终确认的时间,降低大宗交易的确认速度(大额交易要结果不可逆转,才能保障安全)。
简要概括,L2 发生的交易只有发布到 DA 层区块内,且 DA 层又新产生了一定量的区块后,才具备不可逆转性,这是限制 Rollup 性能的一个重要原因。但以太坊出块速度慢,12 秒才出一个块,假设 Rollup 每隔 15 个区块发布一个 L2 批次,不同批次间会有 3 分钟的间隔,而且每个批次发布后,还要等待多个 L1 区块产生,才会不可逆转(前提是不会被挑战)。显然以太坊 L2 上的交易从发起到不可逆转,等待时间很长,结算速度慢;而 BNB Chain 只需 3 秒就可以出一个块,区块不可逆转只需要 45 秒(产生 15 个新区块的时间)。
根据目前的参数,在 L2 交易数量相同且考虑到 L1 区块不可逆转性的前提下,单位时间内opBNB 发布交易数据的次数,最多可以达到 Arbitrum 的 8.53 倍(前者 45s 发一次,后者 6.4min 发一次),显然 opBNB 上大额交易的结算速度,要比以太坊 L2 快很多。同时,opBNB 每次发布的最大数据量,可以达到以太坊 L2 的 4.66 倍(前者 L1 区块的 gas 上限 1.4 亿,后者是 3000 万)。
8.53*4.66=39.74,这就是 opBNB 目前实践中,与 Arbitrum 在 TPS 极限上的差距(目前 ARB 为了安全,貌似主动压低了 TPS,但理论上如果要调高 TPS,还是和 opBNB 很多倍)
当然还有更重要的问题需要考虑,就是 DA 层的 gas 费。L2 每发布一个交易批次,都有与 calldata 尺寸无关的固定成本——21000 的 gas,这也是一笔开销。如果 DA 层 /L1 手续费很高,使得 L2 每次发布交易批次的固定成本居高不下,排序器就会降低发布交易批次的频率。同时,在考虑 L2 手续费成分时,执行层的成本很低,大多数时候可以把它忽略,只考虑 DA 成本对手续费的影响。
总结下来,在以太坊和 BNB Chain 上发布同样尺寸的 calldata 数据,虽然消耗的 gas 相同,但以太坊收取的 gas price 约是 BNB chain 的 10—几十倍,传导到 L2 手续费上,目前以太坊 Layer2 的用户手续费大概也是 opBNB 的 10—几十倍左右。综合下来,opBNB 与以太坊上的乐观 Rollup,差别还是很明显的。
但是,扩大 DA 层的数据吞吐量,虽然可以提升整个 Layer2 体系的吞吐量,但对单个 Rollup 的性能提升还是有限,因为执行层处理交易的速度往往不够快,即便 DA 层的限制可以忽略掉,执行层也会成为影响 Rollup 性能的下一个瓶颈。如果 Layer2 执行层的速度很慢,溢出的交易需求就会蔓延到其他 Layer2 上,最终造成流动性的割裂。所以,提升执行层的性能也很重要,是 DA 层之上的又一道门槛。
opBNB 在执行层的加成:缓存优化当大多数人谈到区块链执行层的性能瓶颈时,必然会提到:EVM 的单线程串行执行方式无法充分利用 CPU、以太坊采用的 Merkle Patricia Trie 查找数据效率太低,这是两个重要的执行层瓶颈所在。说白了,对执行层的扩容思路,无非是更充分的利用 CPU 资源,再就是让 CPU 尽可能快的获取到数据。针对 EVM 串行执行和 Merkle Patricia Tree 的优化方案往往比较复杂,并不是很好实现,而投入性价比更高的工作常聚集在对缓存的优化上。
其实缓存优化问题,回到了传统 Web2 乃至教科书中经常讨论到的点。
通常情况下,CPU 从内存读取数据的速度,是从磁盘读取数据速度的上百倍,比如一段数据,CPU 从内存中读取只需要 0.1 秒,从磁盘中读取则需要 10 秒。所以,降低在磁盘读写上产生的开销,也即缓存优化,成为了区块链执行层优化中必需的一环。
在以太坊乃至绝大多数公链中,记录链上地址状态的数据库被完整存储在磁盘当中,而所谓的世界状态 World State trie 只是这个数据库的索引,或者说查找数据时用到的目录。EVM 每次执行合约都需要获取相关的地址状态,如果数据都要从存放在磁盘里的数据库中一条条拿过来,显然会严重降低执行交易的速度。所以在数据库 / 磁盘之外设置缓存,是必要的提速手段。
opBNB 直接采用了 BNB Chain 用到的缓存优化方案。按照 opBNB 的合作方 NodeReal 披露的信息,最早的 BSC 链在 EVM 与存放状态的 LevelDB 数据库之间设置了 3 道缓存,设计思路类似于传统的三级缓存,把访问频率更高的数据放到缓存中,这样 CPU 就可以先去缓存中寻找需要的数据。如果缓存的命中率足够高,CPU 就不需要过分依赖磁盘来获取数据,整个执行过程的速度就可以实现大幅提升。
后来 NodeReal 在此之上增设了一个功能,调动 EVM 没占用的空闲 CPU 核心,把 EVM 未来要处理的数据,提前从数据库中读出来,放入缓存中,让 EVM 未来能从缓存直接获得需要的数据,这个功能被称为「状态预读」。
状态预读的道理其实很简单:区块链节点的 CPU 是多核心的,而 EVM 是单线程的串行执行模式,只用到 1 个 CPU 核心,这样其他的 CPU 核心就没有被充分利用。对此,可以让 EVM 没用到的 CPU 核心帮忙做点事,它们可以从 EVM 未处理的交易序列中,获知未来 EVM 会用到的数据都有哪些。然后,这些 EVM 之外的 CPU 核心,会从数据库中读取 EVM 未来会用到的数据,帮 EVM 解决数据获取上的开销,提升执行速度。
在对缓存进行了充分优化后,搭配上性能足够的硬件配置,opBNB 其实已经把节点执行层的性能逼近到了 EVM 的极限:每秒最多能处理 1 亿 gas。1 亿 gas 基本就是无改动的 EVM 的性能天花板(来自于某明星公链的实验测试数据)。
具体概括的话,opBNB 每秒最多可处理 4761 笔最简单的转账,处理 1500~3000 笔 ERC20 转账,处理约 500~1000 笔 SWAP 操作(这些数据根据区块浏览器上的交易数据获知)。以目前的参数对比看的话,opBNB 的 TPS 极限,是以太坊的 40 倍,BNB Chain 的 2 倍多,Optimism 的 6 倍多。
当然,以太坊 Layer2 因为 DA 层本身的严重限制,执行层根本施展不开,如果把此前曾提到的 DA 层出块时间、稳定性等因素都考虑进去,以太坊 Layer2 的实际性能要在执行层性能基础上大打折扣。而对于 BNB Chain 这样的高吞吐量 DA 层而言,扩容效应达到 2 倍多的 opBNB 是很有价值的,更何况这样的扩容项目 BNB Chain 可以搭载多个。
可以预见的是,BNB Chain 已经把 opBNB 为首的 Layer2 方案列入自己的布局计划中,未来还会不断收纳更多的模块化区块链项目,包括在 opBNB 里引入 ZK proof,并搭配 GreenField 等配套基础设施来提供高可用的 DA 层,尝试与以太坊 Layer2 体系竞争亦或合作。在这个分层扩容已成为大势所趋的时代背景下,其他公链是否也会争相模仿 BNB Chain 扶持自己的 Layer2 项目,一切都有待时间去验证,但毫无疑问的是,以模块化区块链为大方向得到基础设施范式革命正在且已经发生了。