ULTRA TX:用单个交易实现可编程L1区块
ULTRA TX 是一种通过单个强大 L1 交易实现可编程 L1 区块的方法,结合 L1 元交易打包器和Based Rollup 的区块构建器形成主构建器,用于构建包含超交易的 L1 区块。
什么是 ULTRA TX
ULTRA TX 是一种实现可编程 L1 区块的方式,解锁了远超标准 L1 交易在 L1 区块中能实现的能力。你可以说,ULTRA TX 对于区块的意义,就如同账户抽象对于 EOA 的意义。
本文重点讨论这对 L2 以及 L1 与 L2 互操作性的意义。其他可能的用例不在本文探讨。
当你将 L1 元交易打包器与基于 L1 的 Rollup 区块构建器结合,就得到了一个我们称之为 主构建器 的实体。主构建器将构建仅包含一个极其强大且臃肿的单笔 L1 交易的 L1 区块。这笔单一交易在下文中将被称为 ULTRA TX。
这种设置为 L2 和 L1 的组合性与聚合提供了高效且直接的实现方式。
为了便于 L1 组合性,ULTRA TX 应位于 L1 区块的顶部,以便最新的 L1 状态直接可用。
该方法无需对 L1 进行任何更改。
为什么
- 跨交易强制执行某些条件是噩梦,往往根本不可能。
- 使用 EOA 交易进行 L1 → L2(如存款)非常不便,尤其是对于同步组合性。下文会解释原因。
- 所有(或几乎所有)L1 交易都将是账户抽象交易。EOA 交易存在局限性,应逐渐被淘汰。这不仅是为了改善用户体验,也是为了提高效率。借助 EIP-7702,基于智能合约的账户现在也只需一次签名即可创建,因此用户很容易选择加入。
- L2 希望一起提出/结算(以共享 blob 和证明聚合),并且为了效率和用户体验,频率要高(理想情况是每个 L1 区块)。
- 更具扩展性的 L1 为更好的用户体验铺平了道路。
- L1 上的一个账户抽象交易打包器是最有效的。
- 所有基于 L1 的 Rollup 共用一个区块构建器是最强大的。
基于这些原因,我相信我们正走向一个几乎所有事务都由单笔 L1 交易完成的未来。ULTRA TX 可以逐步采用,区块的其余部分仍可按传统方式构建。
结合实时证明(在合理的容量下),这可以实现理想的未来:以太坊真正像一条单一链,L1 和所有 L2 可以相互调用,每个 L2 可以(但不需要)在每个 L1 区块中进行结算,通常不会损失效率。
接下来,我们经常会引用 Gwyneth 来更具体地说明事情如何实际运作。仅仅因为这是我最熟悉的系统。
优势
- L1 与 L2 之间无缝且简单的聚合与交互: L1 和 L2 交易可以用几乎相同的方式构建区块,共享内存池。这消除了必须区别处理 L1 交易所带来的复杂性和效率考量。下文将说明如何实现。
- 共享数据压缩和数据聚合到 blob: 所有 Rollup 数据可以共享并一起存储在 blob 中。
- 原子性: 现在可以通过可编程逻辑来跨交易强制执行某些条件。所有逻辑都可以通过智能合约实现。
- 可证明性: 整个 ULTRA TX 可以轻松证明,因为所有输入都直接可用。任何需要被证明的操作都可以依赖于它已被证明,否则整个 ULTRA TX 将回滚。相比于无法跨交易强制执行任何条件的普通交易,这是一个重大改进。
- 效率: 所有需要证明的内容只需一个证明即可完成。没有存储或发送消息的开销。L1 → L2 调用如果有返回值则是例外,但可以使用相对便宜的瞬态存储。
- 访问最新 L1 状态: ULTRA TX 位于区块顶部非常重要,这样最新 L1 状态就可以直接从前一区块的区块头中获取。这避免了在 L1 区块的任意位置获取/确保最新 L1 状态的困难/低效(例如,无需通过 EIP-7814 来跨交易边界推理)。像 EIP-7862 中的延迟状态根计算应该影响不大,因为区块仍然可以在新 L1 区块到来后立即构建。但是,为了能够证明 L1 状态,证明者必须针对该状态根拥有所有已使用状态的默克尔证明。
- 预确认: 只需要 L1 区块顶部的“包含”预确认,例如网关可以提供 L1 和 L2 执行预确认。可以通过一个技巧在链上检查一笔交易是否为区块中的第一笔交易:将交易的 Gas 限制设置为区块 Gas 限制,并检查:
block.gaslimit - gasleft() - intrinsic_gas_cost < 21000。这使得即使在今天,在 L1 上强制执行这一要求也没有问题。 - 可定制的安全性: DApp/用户可以轻松选择自己的安全级别,通过在 L1 或 L2 上执行交易。L1 交易仍然可以享有完整的 L1 安全性,这些交易的安全性仅取决于使用扩展功能时证明的有效性。
- 逐步采用: 交易仍然可以放在 ULTRA TX 之后。这允许逐步采用这种新的交易打包方式。这也可以用来限制需要在 12 秒内证明的工作量。随着证明者速度更快、能力更强,ULTRA TX 可以包含越来越多的交易。一个区块中也可以没有 ULTRA TX。或者只有一个仅包含 L2 交易的 ULTRA TX。对于额外工作要么不盈利要么根本不可能(例如,L1 验证者必须构建自己的区块)的区块,L1 区块仍然可以像往常一样构建。
劣势
-
与 L1 的同步组合性需要实时证明: 目前还不可能在 10 秒内用 zk 证明 L1 区块。预计在一两年内 zk 证明者将能够实现实时证明。在此之前,TEE 和诸如 AVS 之类的解决方案是合理的方案,让我们得以一窥未来。
-
L1 组合性要求位于区块顶部: 区块顶部是最有价值的区块空间,因此这一要求可能有问题。然而,L1 元交易现在也可以轻松包含在 ULTRA TX 中,因此高价值的 L1 交易仍然可以优先包含而没有任何问题(构建者只需注意这些状态变化如何影响后续交易即可)。
当区块不需要与 L1 有同步组合性时,可以取消顶部区块的要求。当仅在链上检查所依赖的 L1 状态是否为最新值(然后可以将其提交给 L1 构建者并具有回滚保护)时,也可以取消该要求。但这会影响效率,并且哪些 L1 状态可以轻松在链上读取是有限制的。
-
区块构建者的复杂度增加: 要充分利用该系统,需要具有高硬件要求的复杂区块构建者。这通常对于今天的区块构建者来说已经成立,但这种方法在证明要求以及能够运行 L2 节点(或至少能够协调它们的构建)方面更进一步,以保持竞争力。
-
随时需要 EVM 等价: 需要能够精确地按照 L1 上的执行方式在 L2 上证明/模拟 L1 交易。这就要求整个系统在以太坊硬分叉的同时进行更新。既然证明者现在能够获取现有的执行客户端并证明相同的代码,这不太可能成为问题。
-
以太坊生态系统的选择加入: 要为用户提供可靠的 L1 互操作性,大多数 L1 区块都需要构建带有 ULTRA TX 的区块。
-
L1 交易证明开销: 包含在 ULTRA TX 中的 L1 交易也需要被证明。这可以通过其他方法避免,但同时也节省了链上消息传递的开销。假设有数十个甚至数百个 L2 处理大多数交易,那么证明额外一条链的交易似乎并不比其带来的好处带来显著的开销。
-
用户选择加入智能合约账户: 该设计不一定要求用户在 L1 上拥有智能合约账户,但实际上,这可能是唯一得到良好支持的流程。如果用户不关心额外的好处,他们仍然可以继续使用传统交易。然而,他们可能不会被当作一等公民对待。
EOA L1 → L2 的限制
使用 EOA 交易做好 L1 → L2 很困难。在 L1 上你能做的非常有限:
- 你在 L1 交易中提议一个实际的 L2 交易。理论上可行,但问题在于,如果不先执行该交易,通常无法知道这些 L1 交易最终会提议一个 L2 交易。这个 L2 交易随后还得以某种方式进入 L2 区块,同时又不属于 L2 区块构建过程的一部分。当单个预确认者被赋予唯一的提议权时,这也可能成为问题。
- 如果 L1 → L2 调用需要返回值,那么交易中还需要提供一个证明。用户需要签署额外数据作为其交易的一部分,而这些数据可能在交易上链之前就已过期。这导致糟糕的用户体验。如果有很多 L1 → L2 交互,那也意味着很多证明需要在链上验证,这使得效率非常低下。
- Gwyneth 允许在 L2 上发起 L1 工作。然而,某些操作(例如从账户中转出 ETH)在没有所有者签名的真实 L1 交易的情况下是不可能完成的。账户抽象解决了这个问题,因为现在所有账户修改都可以同时通过 L1 交易和 L2 交易来支持。
扩展 L1
L1 功能可以通过在外部调用后面放置额外功能来扩展(可能类似于原生 Rollup 的可扩展方式)。在 Gwyneth 的情况下,这个调用是对 L2 的跨链调用。在构建和证明区块时,区块的创建就好像这个额外功能也在 L1 上可用。这些调用的输出被收集并作为 ULTRA TX 的一部分发送到链上:
- 由 L1 上调用的扩展生成的输出存储在
ExtensionOracle合约中。这些值在作为 ULTRA TX 一部分的调用执行之前设置。ExtensionOracle是一个简单的合约,它为 L1 实际上不支持每个调用提供输出。此数据存储在瞬态存储中。 - 现在我们可以实际执行调用。每次对扩展功能的调用都会检查当前执行环境中是否支持该调用:
- 如果支持,则正常执行调用。例如,调用实际发送到目标合约。这是构建者/证明者所遵循的路径。
- 如果不支持,则意味着该调用应重定向到
ExtensionOracle智能合约,该合约将读取链下生成的调用输出。这是 L1 上遵循的路径。
- 最后,验证证明,显示一切按预期完成。
这些额外数据由主构建者生成和提供,而不是由用户提供。用户无需签署任何额外数据或验证昂贵的证明。用户可以使用扩展功能与智能合约交互,其方式与使用原生功能完全相同。
在智能合约中使用扩展功能的开发者也不必知道幕后实际发生了什么。
请注意,这种方法之所以有效,完全是因为 Gwyneth 可以“模拟”L1 交易的执行以将所有内容粘合在一起。在证明者中,L1 交易的执行方式与 ULTRA TX 被提议时在 L1 上的执行方式相同。这对于确保使用正确的输入生成输出非常重要。
(同步)组合性
我将再次使用 Gwyneth 的同步组合性方法作为示例(你可以快速阅读这里,还有这里、这里和这里)。简而言之,L2 上添加了一个额外的预编译,允许在外部调用时切换链。Gwyneth 还可以模拟所有 L1 交易,然后仅将状态更新应用回 L1。
这里我要做的假设是:每个 L1 账户都是智能合约账户,并且所有 L2 都是基于 L1 的(多么美好的假设!)。
现在可以轻松地按如下方式构建区块:
- 我们从每条链(包括 L1)的 post 状态开始。L1 和 L2 交易之间没有区别(除了 L1 交易应该是元交易,如果不是,则在 ULTRA TX 之后添加到 L1 区块)。
- L1/L2 交易以构建者想要的任何顺序执行。
- 对于 L1 交易,修改 EVM 执行,使得
XCALLOPTIONS预编译的工作方式与 L2 完全相同(即,它实际执行对目标 L2 的调用),如上文“扩展 L1”部分所述。这允许 L1 交易调用 L2,这是支持真正的同步组合性所必需的。 - 对于任何 L1 → L2 调用,我们记录对应的调用输出。
- 一旦构建者在本地执行完所有必需的交易,我们就可以打包区块:
- 对于 L2,将交易或状态增量放在 L1 上用于数据可用性。这是为每个 L2 独立完成的,这样它们之间就没有相互依赖关系。区块哈希可以聚合后放在链上以节省 Gas。
- 对于 L1,我们需要按预期顺序在链上应用所有状态变化,就像它们在构建者中发生的那样。对于 Gwyneth,这意味着按正确顺序应用 L1 交易和 L1 状态增量(用于从 L2 完成的 L1 状态更改)。
构建过程可以根据需要重复多次,以生成任意数量的区块。这对于支持比 L1 区块时间更快的交易执行预确认可能很重要。并行化区块构建(见下文)也很重要。
最后,为整个过程生成一个单一的证明(注意,这可能包含子证明,见下面的并行化部分)。
然后 ULTRA TX 最终在链上被提议。交易的所有输入都被用作证明的输入,并验证证明。如果证明无效,则整个交易回滚。
请注意,构建者为了正确包含交易而必须支持的任何额外要求都可以作为交易的元数据的一部分。这样,构建者无需执行交易即可轻松查看他们是否能够包含该交易。这些规则可以在链上强制执行。例如,对于跨链交易,元交易将包含允许访问的链列表。如果此列表不完整,则允许交易回滚,构建者获得交易费用。
并行化
上述简化过程是严格顺序的,以便所有链能够以最简单的方式自由地同步交互。如果它们之间不需要同步,也可以并行地为任意链集构建区块。可以提交多个区块,效率几乎相同。这打破了顺序瓶颈,可以实现更高的吞吐量。
即使例如某条链有 L1 状态依赖,仍然可以并行构建区块。只有区块中使用的状态子集对于区块有效来说必须是实际的最新值。
在这些区块之上可以有一个额外的层来跟踪全局状态,而每个区块只直接依赖于这个子状态。每个区块单独证明,然后与额外的状态检查一起聚合。聚合证明将跨区块跟踪最新的全局状态,并检查区块中使用的本地状态是否与当前最新的全局状态匹配。构建者只需在并行构建区块时确保这些假设成立即可。
泛化
关于如何(以及更多)将此用于所有 Rollup(不仅仅是 Gwyneth 的)的泛化将在第 2 部分中介绍。该框架将被称为 GLUE。之前的草稿在这里。它将相当深入地包含链下和链上必要的接口,以使所有 L1 扩展能够利用所提出的设计。
代码
一些让事情更具体、更有趣的代码。为简洁起见省略了一些细节。
ULTRA TX 在链上可能的样子:
function proposeBlock(BlockMetadata[] calldata blocks) external payable {
for (uint i = 0; i < blocks.length; i++) {
_proposeBlock(blocks[i]);
}
_prove(blocks);
}
function _proposeBlock(BlockMetadata calldata _block) private {
for (uint i = 0; i < _block.l1Block.transactions.length; i++) {
Transaction calldata _tx = _block.l1Block.transactions[i];
for (uint j = 0; j < _tx.calls.length; j++) {
Call calldata call = _tx.calls[j];
// 在 ExtensionOracle 中设置返回数据
if (call.returnData.length > 0) {
(bool success, bytes memory result) = address(extensionOracle).call(abi.encode(call.returnData));
require(success == true, "call to extension oracle failed");
}
// L1 账户抽象调用
_tx.addr.call{value: call.value}(call.data);
}
// 必要时应用 L1 状态差异
if (_tx.slots.length > 0) {
GwynethContract(_tx.addr).applyStateDelta(_tx.slots);
}
}
}
对于想要利用扩展功能的开发者来说,它看起来像这样:
using EVM for address;
function xTransfer(uint256 fromChain, uint256 toChain, address to, uint256 value) public returns (uint256) {
return on(fromChain)._xTransfer(msg.sender, toChain, to, value);
}
function ChainAddress(uint256 chainId, xERC20 contractAddr) internal view returns (xERC20) {
return xERC20(address(contractAddr).onChain(chainId));
}
function on(uint256 chainId) internal view returns (xERC20) {
return ChainAddress(chainId, this);
}
扩展如何向开发者公开:
library EVM {
function xCallOptions(uint chainID) public view returns (bool) {
// 调用自定义预编译
bytes memory input = abi.encodePacked(version, chainID);
(bool success, bytes memory result) = xCallOptionsAddress.staticcall(input);
return success && bytes4(result) == xCallOptionsMagic;
}
function onChain(address addr, uint chainID) internal view returns (address) {
bool xCallOptionsAvailable = xCallOptions(chainID, false);
if (xCallOptionsAvailable) {
return addr;
} else {
return extensionOracle;
}
}
}
Extension Oracle 的样子:
contract ExtensionOracle {
uint private transient returndataCounter;
ReturnData[] private transient returndata;
fallback() external payable {
_returnData();
}
receive() external payable {
_returnData();
}
function _returnData() internal {
if (msg.sender == gwyneth) {
returndata = abi.decode(msg.data, (GwynethData.ReturnData[]));
} else {
require(returndataCounter < returndata.length, "invalid call pattern");
ReturnData memory returnData = returndata[returndataCounter++];
bytes memory data = returnData.data;
if (returnData.isRevert) {
assembly {
revert(add(data, 32), mload(data))
}
} else {
assembly {
return(add(data, 32), mload(data))
}
}
}
}
}
- 原文链接: ethresear.ch/t/ultra-tx-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~


