Block-STM 怎么并行执行交易?推测、验证与按序重执行的路线对比 图 1
Block-STM 怎么并行执行交易?推测、验证与按序重执行的路线对比 · 图 1

两条并行化路线:先声明,还是先干了再验证

公链执行交易的传统方式是逐笔串行:前一笔执行完才能跑下一笔,长交易堵住后面的所有交易。要提速,就得让互不相干的交易同时执行。难点在冲突:两笔交易如果读写同一个存储位置,就不能都按”只有自己一个人跑”的方式提交。目前的主流方案分成两派。一派是静态并行:要求交易在提交时声明自己会碰哪些账户或键,调度器据此把不相交的交易编排到不同执行单元,Solana 要求交易声明读写账户就属于这一类。另一派是动态并行:交易什么都不声明,引擎先推测执行,运行时发现冲突再处理,Aptos 使用的 Block-STM 是这一派的代表。官方文档对两派的取舍说得很直白:静态路线把负担推给应用开发者,而且声明的访问集合通常比实际用到的更宽,本来并行的活被迫串行。

Block-STM 的三步循环:推测、验证、按预设顺序重执行

机制示意:多条推测执行通道汇入按预设顺序合并的单条确定性输出轨道(图片由 Agnes 生成,非产品界面或链上数据图)

Block-STM 的思路借自软件事务内存:一个区块里的所有交易被多线程同时启动,每笔交易先推测性地读取当前估计值并写下带版本号的猜测写入。执行完成后进入验证:检查这笔交易当初读到的每个值,是否仍然是按预设顺序执行时应当读到的值。读集没被更靠前的交易改写,交易就提交;否则中止并按预设顺序重执行。关键约束是:并行只是加速手段,最终状态必须与严格按共识顺序逐笔执行完全一致——引擎利用这个”预设顺序”来定义谁先谁后:发生冲突时,总是让顺序靠后的那笔重跑,而不是协商一个折中结果。Block-STM 论文把大部分工程创新放在执行任务与验证任务的协作调度器上:空闲线程可以随时去验证别人能观察到的读依赖,而不是傻等,这让它在不同冲突率的负载下都能利用硬件并行度。

为什么结果仍然确定:预设顺序是唯一的裁判

推测执行听起来像”先到先得”,其实排序早在共识阶段就定死了:区块里交易列表的顺序就是唯一合法顺序,并行执行结束后要做的只是证明”并行跑出来的状态等于串行跑出来的状态”。这就带来两个实际含义。对开发者:写合约不需要为并行做任何声明,也不存在”我的交易和别人的声明冲突所以排队”这种体验问题;Gas 计费按实际执行的路径计算,同一笔交易在不同并行环境下计费可能不同,但状态结果是确定的。对节点运维:Block-STM 的收益与硬件线程数和负载冲突率相关——官方论文的基准测试显示在低冲突负载下相对串行基线有数量级的提升,而在高冲突负载下收益明显收窄,所以压测数字不能跨负载场景照搬。

和静态路线逐项对比

声明式路线(以 Solana 的账户声明模型为代表)与 Block-STM 的差异可以逐项列:信息获取时机——前者运行时前由开发者提供,后者运行时由引擎探测;出错代价——声明漏了直接交易无效要重发,推测冲突只是重执行浪费算力;对陌生合约的适配——静态路线要求程序把所有可能被间接访问的账户也列全,动态路线天然覆盖未预料的依赖;CPU 利用率——静态路线编排不当会出现执行单元空转,动态路线用调度器填谷。两条路线也在互相借鉴:以太坊的并行执行研究采用区块级访问清单做调度,属于静态思路的新发展,而 Aptos 官方文档提到 Polygon、Sei、Starknet 等链也采用了 Block-STM 的动态并行思路。选型没有绝对优劣:账户模式固定、访问模式可预测的链适合静态;EVM 语义、合约间调用复杂的链更适合动态。

什么时候并行帮不了你

三类负载会从并行收益里掉出去:热点冲突型(所有交易抢同一个池子或同一个代币的流动性,重执行率飙升)、长尾大交易型(单笔执行时间远超重执行开销,调度器只能等它)、以及依赖前一笔输出的链式调用(本质仍是串行)。判断一条链宣传的性能数字时,先看它用什么冲突率的负载测出来的,比对比线程数更有意义。本文只做机制解释,不构成任何投资建议。