主页 > imtoken官网注册 > 简介 | 以太坊第 2 层的通用桥

简介 | 以太坊第 2 层的通用桥

imtoken官网注册 2023-07-04 05:11:21

随着越来越多成熟的以太坊 Layer-2 解决方案,ENS 也必须能够为整个生态系统提供服务,同时让 ENS 用户获得 Layer-2 解决方案带来的效率提升。 由于 Vitalik 的一篇帖子提出了一种可能的方法,ENS 团队和更广泛的 ENS 和 L2 社区也一直在开发通用的“第 2 层桥接器”,以允许包括 ENS 在内的应用程序变得无需信任。以独特的方式链接资源,实现跨平台互操作性。

在 10 月 27 日最近的一次工作会议上,我展示了这个想法的初步实现。 在这篇文章中,我将详细解释这个解决方案。

目标

简而言之,Layer-2 和其他相关系统的工作原理是减少与以太坊交互的需要。 他们将链上需要保存和访问的状态转移到其他地方,同时保证以太坊区块中的状态有足够的链上信息来验证数据的正确性。 比如像Rollup这种常见的方案,(Rollup的)状态存储在另一个系统中,只有Merkle根等见证数据存储在以太坊区块链上(译者注:作者这里的例子并不完整,并且见证还包括用户交易的原始数据)。 通过访问这些见证数据和 Layer-2 解决方案,参与者可以构建 Layer-2 系统中保护的任何数据的有效性证明,并可以由以太坊进行验证。

这个定义比大多数人认为的“第 2 层”更广泛——它还包括其他工具来减少链上数据存储,例如使用 Merkle 账户余额树的空投,以及触发事件但不存储余额——链。

对于 ENS 和其他应用程序,关键问题是,在许多不兼容的 Layer-2 方案的世界中,我们如何才能最小化信任——即在不引入任何新的信任假设的情况下——从某个系统中检索数据,并且不需要成为所有 Layer-2 解决方案的客户端,以自行存储潜在有用的数据。

sitehqz.com 以太坊交易查询_怎么查询以太坊的交易记录_如何查询以太坊钱包转账记录

一种天真的方法是要求所有系统使用相同的见证数据格式。 但这是不可能的,原因有二:第一,见证数据的格式和类型高度依赖于相关系统的实现细节,ZK Rollup 和 Optimistic Rollup 使用的组件肯定是不同的; 第二,客户端仍然无法真正获取到数据。

实用的方法必须满足以下条件:

解决方案概述

我们提出的解决方案的核心是一个标准化工具,它使客户能够从外部系统检索数据——一种网关服务——以及一种验证返回数据是否正确的标准化方法。 相应地,这里有两个主要组件:第一个是放置在以太坊 Layer-1 上的智能合约怎么查询以太坊的交易记录,它为客户端提供了一个工具来发现网关并验证网关响应的正确性; 第二个是网关服务,了解如何与给定的 L2 系统交互以及如何为合同目的格式化数据。 在该模型下,获取数据的过程分为三个步骤:

sitehqz.com 以太坊交易查询_怎么查询以太坊的交易记录_如何查询以太坊钱包转账记录

如何查询以太坊钱包转账记录_怎么查询以太坊的交易记录_sitehqz.com 以太坊交易查询

向合约发送请求以查询数据。 合约不会直接返回想要的结果,而是返回两个值:网关 URL 和调用数据前缀。 向网关发送 HTTP POST 请求,请求与第一步相同的数据。 网关返回一个不透明值(opaque value),解析器(parser)调用数据。 验证parser的calldata的起始位是否为第一步得到的calldata前缀。 查询合约,或与之交互,提供第二步得到的parser calldata,合约验证数据的有效性,如果有效则返回结果或执行交易。 因为负责理解如何与 L2 交互的是网关服务,所以这样一个简单的协议允许客户端在链下获取数据,而不需要客户端理解任何与 L2 相关的内容。 为了使用这个系统,每个应用程序都需要为它打算与之交互的 L2 实现和部署一个网关服务和一个验证合约。 在大多数用途中,这些网关可以非常通用,从而减少不同应用程序之间重复工作的负担。 重要的是这三个步骤的过程可以在调用者处完全抽象掉; 理解这个协议的库可以让整个过程看起来像一个常规的 web3 合约调用,也就是说,不仅应用程序不需要知道他们正在与哪个 L2 交互怎么查询以太坊的交易记录,他们甚至不知道他们正在与 L2 交互全部! 网关返回错误或误导性结果的能力受到协议本身的限制。 合约实现的验证逻辑可确保在第三步中发现任何无效结果。 同时在第二步验证第一步合约返回的前缀; 响应另一个查询的有效答案。 工作示例我们可以演示该系统在实践中如何使用预加载了一组余额的 ERC20 代币合约,以及一个本身就是简单静态 Merkle 树的“第 2 层”:

contract PreloadedToken is ERC20 {  mapping(address=>uint) preload;  function claimableBalance(address addr) external view returns(uint) {    return preload[addr];  }  function claim(address addr) external {    if(preload[addr] > 0) {      _mint(addr, preload[addr]);      preload[addr] = 0;    }  }}

这个简单的解决方案有一个明显的问题:部署者必须在部署时将所有余额填充到预加载映射中,这是一个非常昂贵的操作。 他们更愿意将数据存储在链下,让能够证明自己有余额的用户提取自己的金额。 这很容易通过 Merkle 树实现:

contract PreloadedToken is ERC20 {  bytes32 merkleRoot;  mapping(address=>bool) claimed;  function claimableBalanceWithProof(address addr, uint balance, bytes proof) external view returns(uint) {    require(verifyProof(keccak256(addr, balance), proof));    if(!claimed[addr]) {      return balance;    }    return 0;  }  function claimWithProof(address addr, uint balance, bytes proof) external {    require(verifyProof(keccak256(addr, balance), proof);    if(claimed[addr]) {      return;    }    _mint(addr, balance);    claimed[addr] = true;  }}

(为简单起见,我们省略了verifyProof(验证证明函数)的实现)

sitehqz.com 以太坊交易查询_怎么查询以太坊的交易记录_如何查询以太坊钱包转账记录

这种方法非常有效,合约作者不再需要花费大量的eth来预加载所有余额。 一个 merkle root 就够了,当调用者想要取回余额时,他可以支付证明代币所有权的开销。 但是,现在调用者必须了解生成证明的具体过程,知道从哪里得到余额列表来生成自己账户的证明。 如果我们能够将第一个解决方案的界面(便利性)与第二个解决方案的效率结合起来,那就太完美了。 这是我们的解决方案。 首先,我们添加与原始声明的签名和 claimBalance 相匹配的方法:

  string gateway;  function claimableBalance(address addr) external view returns(bytes prefix, string url) {    return (abi.encodeWithSelector(claimableBalanceWithProof.selector, addr), gateway);  }  function claim(address addr) external view returns(bytes prefix, string url) {    return (abi.encodeWithSelector(claimWithProof.selector, addr), gateway);

这些函数的调用者可以获得两个值:第一个值是后续回调的前缀; 第二个值是网关服务的 URL。 这个前缀保证了两件事:回调将使用关联的证明函数进行响应,并且它的第一个参数将是提供的地址。 这可以防止网关使用用于另一个地址的数据来响应请求。

接下来,我们需要实现一个网关服务来满足客户端的查询请求。 以claim1为例,可以直接实现:

const args = tokenInterface.decodeFunctionData("claim", data);const balance = balances[args.addr];const proof = merkleTree.getProof(addr, balance);return merkleInterface.encodeFunctionData("claimWithProof", [args.addr, balance, proof]);

sitehqz.com 以太坊交易查询_如何查询以太坊钱包转账记录_怎么查询以太坊的交易记录

(同样,为简洁起见,我们假设包含 getProof 函数的合适实现已经存在)

这里的网关服务只需要对客户端发送的claim调用的函数调用数据进行解码,组装证明——或者,在实际的L2方案中,参考L2组装证明——然后将结果编码到claimWithProof 的调用,返回给客户端。 最后,客户端验证返回的调用数据是否以合约断言的前缀开头,如果是,则使用事务将调用数据发送给合约。 claimableBalance的实现类似,只是客户端使用calldata调用合约,返回值作为调用的最终结果。

安全注意事项和信任模型

假设客户信任原始合约——我们的意思是合约预期以某种方式运行,这可以通过检查其发布的源代码来验证——那么系统不会引入任何新的信任假设。 虽然网关的响应是一个外部进程,但其不良行为的范围仅限于拒绝服务。 首先,如果我们信任合约,我们也相信它会制定一个网关 URL 来响应我们的查询。 其次,我们还可以相信它会执行充分的验证以确保网关的响应是准确的,无论是通过在第一步中指定 calldata 前缀,还是通过在最后一步中验证网关的响应。 因此,尝试以不正确的值进行响应的网关——无论是通过提交不正确的数据还是不正确的证明——将被执行验证步骤的合约发现。 尝试正确响应但响应结果与用户发出的请求不对应的网关将在用户的呼叫数据前缀检查中被发现。 客户端可以在开始交互之前通过检查合约的行为来确保这一点——或者依赖某人对合约的检查。 网关可以简单地拒绝响应,也就是拒绝服务,这确实可能是由于恶意或故障网关而发生的。 正因为如此,我们建议任何最终规范都应该让用户能够轻松地分叉服务并提供自己的网关; 就像今天用户能够分叉 dApp 前端一样。

ENS申请

怎么查询以太坊的交易记录_如何查询以太坊钱包转账记录_sitehqz.com 以太坊交易查询

ENS 也将相对直接地使用该系统。 解析器可以实现本文描述的协议来解析任何数据字段,然后每个希望支持 ENS 数据存储和检索的 L2 可以部署新的解析器实现和相应的网关。 希望使用 L2 的用户只需将他们的记录存储在适当的 L2 中,并在以太坊上发送一次性交易,指定相关的解析器地址以使用他们的域名。 为了让这个方案更通用,ENS 也应该被改进以支持某种形式的通配符解析,这样当一个域名搜索失败时,向解析器咨询该域名的父域名——如果“foo.example.eth " 不存在,客户端将在解析器中搜索 "example.eth"。 此功能允许其他系统存储 ENS 的整个子树,而不仅仅是单个域名的记录。

尚未解决的问题

自己试试我文章中所有演示的源代码都可以在这里找到。

(结束)

(本文链接较多,可点击左下方“阅读原文”从EthFans网站获取)

原文链接: