您正在查看: Ethereum-优秀转载 分类下的文章

使 Solana 用户能够访问在 Solana 上运行的 EVM dApp

随着本白皮书的发布,Neon EVM 引入了多项功能,以统一 Solana 与部署在 Neon 上的 EVM dApp 之间的用户体验。此版本遵循Solana 网络扩展方法中描述的愿景,并描述了 Neon EVM 基础设施的发展方式。

本文描述的概念将会在 SDK 中实现,具体如下:

  • Solana 签名支持:使 Solana 用户能够使用他们现有的 Solana 钱包签署 Neon EVM 交易,从而无需 EVM 签名和钱包。
  • 链上内存池:引入链上系统,无需依赖外部工具即可高效地安排和执行 Neon EVM 交易。
  • 关联 Neon 账户:创建抽象 Solana 地址的 Neon 账户,并实现 Solana 用户和 Neon EVM 之间的无缝交互。
  • Neon 交易的受控树:实现交易的原子和并行执行方法,管理状态变化并聚合复杂交互的结果。
  • 基于意图的执行:提供一种处理交易意图的机制,尽管 Solana 存在局限性,但仍能提高 EVM 合约和 Solana 程序之间的互操作性。

点击此处阅读完整白皮书

挑战:为 Solana 用户解锁以太坊 dApp

Solana 和以太坊是领先的 L1 区块链之一,各自都拥有活跃的 dApp 生态系统和性能优势。然而,这两个环境尚未相互交互,主要是由于编程语言、开发工具和基础设施的差异。

虽然 Neon EVM 允许 EVM dApp 为类似以太坊的用户访问 Solana 代币,但之前的解决方案涉及多个钱包的管理。在 Neon EVM 上执行交易需要使用 secp256k1 椭圆曲线的 EVM 签名,因此必须使用 MetaMask 等 EVM 钱包。这一要求对习惯于 Solana 中使用的 ed25519 签名的 Solana 用户以及无法使用 Phantom、Backpack 和 Solflare 等 Solana 钱包的用户来说是一个重大障碍。

通过下面提出的解决方案,EVM 开发人员可以通过减少碎片化和简化入职培训来原生地利用 Solana 用户群。

探索“Solana-Native”功能

白皮书介绍了 Solana 的各种原生功能。需要关注的五个关键功能包括:

Neon EVM 中的 Solana 签名支持

为了消除 Solana 用户管理额外 EVM 钱包的需要,Neon EVM 修改了其交易验证流程以接受 Solana 的 ed25519 签名。此修改包括:

  • 签名验证适配:调整 Neon EVM 以识别和验证 ed25519 签名。
  • 自定义交易类型:利用交易类型属性定义与 Solana 签名兼容的自定义交易类型,并遵守 EIP-2718 的类型化交易信封。

从技术上讲,Solana 用户的 EVM 地址 (ethAddress) 是使用 Keccak-256 哈希函数应用于 Solana 公钥 (solanaPublicKey) 得出的。地址派生公式为:

此方法采用哈希的最后 20 个字节来形成与 EVM 兼容的地址,从而确保唯一且抗冲突的映射。然后使用 Neon EVM 中的 Solana 原生加密库来验证 Solana 签名,从而确保安全验证。

好处

  • Solana 用户可以使用现有的 Solana 钱包(例如 Phantom/Backpack/Solflare)签署 Neon 交易。此集成减少了用户与 Solana 上的 EVM dApp 交互所需的步骤,并将资产保留在熟悉的 Solana 钱包环境中。
  • 使用 Solana 钱包无需转移资金,只需将 SOL 用作 gas 代币和 Solana 网络 RPC。从用户的角度来看,资产交换是通过发送 SPL 代币并接收所选资产的 SPL 代币来执行的。

创建关联 Neon 账户,统一资产管理

Neon EVM 通过整合 Solana 和 Neon EVM 生态系统来解决流动性分散问题,使用户能够与兼容 EVM 的 dApp 进行交互,而无需进行不必要的资产转移。以前,用户依靠 NeonPass 将 SPL 代币从 Solana 钱包转移到 Neon EVM 账户,这使资产管理变得复杂,流动性也变得分散。现在,随着 ERC20forSPL 合约的引入,这一过程得到了简化,该合约无缝连接了两个生态系统。

拥有 Solana 钱包的用户通过关联代币账户 (ATA) 管理其 SPL 代币。Neon EVM 使用 Keccak-256 哈希将其 Solana 公钥映射到与 EVM 兼容的地址,从而创建一个关联的 Neon 账户,其中包含与 EVM 兼容的地址、Solana 公钥、交易计数器、链标识符和内部余额的字段。

当用户与 Neon EVM 上的 dApp 交互时,ERC20forSPL 合约首先检查其内部余额。如果余额不足,它会查询 Solana 上用户的 ATA 以检索必要的 SPL 代币。此过程消除了 NeonPass 转账的需要,并允许用户在 Neon EVM 中操作,同时将资产保留在 Solana 上。

好处

  • 简化资产管理:用户可以控制其 Solana 钱包中的资产,而无需中间转账(例如通过 NeonPass)。
  • 降低交易成本:通过利用链上余额查询并避免冗余传输,用户在与 EVM dApp 交互时可以降低成本。

使用链上内存池实现高效的交易管理

高效的交易调度和执行管理对于流畅的用户体验至关重要。Neon EVM 实现了链上内存池来存储和管理已调度的 Neon 交易。这允许 Solana 用户直接从他们的 Solana 钱包调度 Neon EVM 交易,Neon 代理会代表他们检测和执行这些交易。

TreeAccount 是一个专用帐户,具有预定的 Neon 交易、余额和执行状态。它包括以下内容:

  • 付款人的 EVM 地址:与 Solana 用户关联的 EVM 地址。
  • 最后一个槽位:修改帐户的最后一个 Solana 槽位。
  • 链 ID:链命名空间的标识符。
  • Gas Limits:允许执行的最大气体量。
  • 余额:为执行交易而保留的资金。
  • 交易清单:预定的 Neon 交易及其执行详情。

交易调度协议涉及用户向 Neon EVM 程序提交 Neon EVM 交易,该程序会验证并将其添加到链上内存池中。然后,Neon 代理会监控内存池并相应地执行交易。

对于超出 Solana 大小限制的较大交易,只有交易哈希存储在链上,完整交易会发送到链下 Neon 代理。这种方法可以实现可扩展性并高效处理较大的交易,而不会影响网络性能。

好处

链上内存池增强了可扩展性,确保了交易完整性,并保持了状态更改的原子性。用户受益于高效的交易管理,开发人员可以利用此系统创建更复杂、响应更快的 dApp

用于复杂交互的受控事务树

为了克服 Solana 的即时状态应用和对交易还原的缺乏支持(这阻碍了 EVM 合约和 Solana 程序之间的复杂交互),Neon EVM 引入了 Neon 交易的受控树。该机制通过在树结构中组织交易来管理复杂的交互场景,其中每个节点代表一个 Neon 交易,父子关系定义执行依赖关系。

主要特点包括:

  • 原子交易:每个 Neon 交易都是原子的,在完成时存储状态变化。
  • 并行执行:没有依赖关系的事务可以并行执行,优化性能。
  • 结果聚合:合约可以生成多个交易,并在后续交易中聚合结果。

好处

  • 这项创新使开发人员能够构建更复杂、更集成的应用程序,通过实现受控状态变化的原子和并行执行来克服限制。
  • 它可以增强交互的稳健性,并通过防止由于单个错误而导致的整个交易失败来改善用户体验。

基于意图的条件交易执行

Neon EVM 采用了意图驱动执行,为用户和开发者提供了根据特定条件或市场状态执行交易的灵活性。意图被定义为指定执行条件的简单 EVM 代码,遵守静态调用规则(不能修改状态)。Neon 代理会在执行交易之前评估这些意图。如果条件不满足,则跳过交易,用户无需支付任何费用。

此功能可以实现:

  • 自动交易策略:仅当市场条件满足特定标准时才执行交易。
  • 条件操作:当链上发生特定事件时执行诸如代币交换之类的操作。

好处

基于意图的执行可以更好地控制交易执行,提高资源效率,并减少用户不必要的成本。它增强了 dApp 对实时情况的灵活性和响应能力。

结论

征求反馈和协作:这份白皮书启动了 Neon EVM 的 Solana 原生演进,寻求不同视角的意见,并促进以太坊和 Solana 社区的开发者参与。
在这里,我们发布了第一稿,并邀请构建者社区积极贡献并开始评估您 dApp 上的实施情况。白皮书可在此处访问

白皮书的第一个功能——即将发布的 Solana 签名钱包 SDK——已付诸实践。Solana 签名功能在 EVM 端已完成,并在代理端部分实现——目前正在测试和审核中。此外,敬请期待即将发布的用例和演示版本!

加入我们,在 Solana 上构建 dApp 的未来。立即探索 Neon EVM!

关于 Neon EVM
Neon EVM 是同类产品中的第一个,是 Solana 上的网络扩展,旨在将以太坊虚拟机 (EVM) 兼容性无缝集成到 Solana 的高性能生态系统中。通过在 Solana 的基础层内本地运行,Neon EVM 为以太坊开发人员提供了一种快速、高吞吐量的途径,可以在 Solana 上部署他们的 EVM dApp,而无需用 Rust 重写他们的合约。

有关 Neon EVM 和未来更新的更多信息,请访问neonevm.org并通过TwitterDiscord与社区联系。

原文:https://neonevm.org/blog/Enabling-Solana-Users-to-Access-EVM-dApps-Running-on-Solana

Beam-SNARK 的工作原理

零知识简洁非交互式知识论证 (Beam-SNARK) 是一种开创性的方法,它允许人们在不透露任何其他信息的情况下证明陈述的真实性。但这为什么有用呢?

零知识证明有广泛的应用场景,例如:

1. 关于私人数据的证明陈述:

  • 确认某人的银行余额超过某个限额,但不透露具体金额。
  • 核实银行在过去一年内没有与特定实体进行过交易。
  • 匹配 DNA 样本但不透露完整的基因图谱。
  • 显示高于一定值的信用评分但不透露详细信息。

2. 匿名授权

  • 证明用户有权访问网站的限制区域,而无需分享其身份(例如登录凭据)。
  • 确认在授权地区的居住权但不透露具体位置。
  • 在不透露身份的情况下验证有效地铁通票的所有权。

3. 匿名支付:

  • 无需关联身份即可进行付款。
  • 不披露收入而纳税。

4. 外包计算:

  • 委托复杂的计算,同时确保结果正确,无需重复工作。
  • 将区块链模型从通用计算转变为一方计算、其他方验证的模型。

零知识证明的底层数学和密码学简直就是奇迹。自 1985 年开创性的论文“交互式证明系统的知识复杂性”以来,该领域已经活跃了四十多年。非交互式证明的引入在区块链环境中尤为关键。

在任何零知识证明系统中,都有两个关键参与者:

  • 证明者:想要让验证者相信某个陈述的真实性的人。
  • 验证者:无需获取任何额外知识即可检查证明者主张的有效性的人。

该系统必须满足三个核心属性:

  1. 完整性:如果陈述是真实的,则证明者可以说服验证者。
  2. 健全性:作弊的证明者无法让验证者相信错误的陈述。
  3. 零知识:交互仅揭示陈述是否真实,而不揭示其他任何内容。

Beam-SNARK 将这些原理应用于通用计算,为实际应用提供了一个优雅的解决方案。

证明的媒介

为了理解 Beam-SNARK,让我们从一个简单的例子开始,而不深入研究零知识或交互性。

假设我们有一个 10 位的数组,并且我们想要向验证者(例如,程序)证明所有位都设置为 1。

假设我们有一个长度为 10 的位数组,并且我们想要向验证者(例如程序)证明所有这些位都设置为 1。

验证者每次只能检查一位。为了验证该声明,验证者可以按随机顺序检查位:

  • 一次成功检查后,验证者对该声明的信心为 10%。
  • 如果某个位为 0,则该断言立即被推翻。
  • 为了获得更高的置信度(例如 50% 或 95%),验证者必须执行更多检查,与阵列的大小成正比。这种方法对于大型数据集来说不切实际。

相反,我们可以利用具有独特属性的多项式。多项式在图形上显示为曲线,由数学方程定义。

上图曲线对应多项式:f(x) = x³ — 6x² + 11x — 6。多项式的次数由其 x 的最大指数决定,在本例中为 3。

多项式有一个优点,即如果我们有两个次数最多为 d 的不相等多项式,它们最多只能在 d 个点处相交。例如,让我们稍微修改一下原始多项式 x³ — 6x² + 10x — 5,并将其可视化为绿色:

如此微小的变化会产生截然不同的结果。事实上,不可能找到两个不相等的多项式,它们共享一条连续的曲线块(单点块的情况除外)。

此属性源自查找公共点的方法。如果我们想找到两个多项式的交点,我们需要使它们相等。例如,要找到多项式与x轴的交点(即f ( x ) = 0),我们使x ³ — 6 x ² + 11 x — 6 = 0相等,并且该等式的解将是这些公共点:x = 1、x = 2 和x = 3,您也可以清楚地看到,在上图上蓝色曲线与x轴线相交的位置,情况确实如此。

同样,我们可以将原始多项式和修改后的多项式相等来找到它们的交点。

所得到的多项式是 1 阶的,显然有一个解x = 1。因此只有一个交点:

对于任意次数为d 的多项式,任何此类方程的结果始终是次数最多为d的另一个多项式,因为没有乘法可以产生更高的次数。例如:5 x ³ + 7 x ² — x + 2 = 3 x ³ — x ² + 2 x — 5,简化为 2 x ³ + 8 x ² — 3 x + 7 = 0。代数基本定理告诉我们,次数为d 的多项式最多可以有d 个解(更多内容见下文),因此最多有d 个共享点。

因此,我们可以得出结论,在任意点处对任何多项式的求值类似于对其唯一身份的表示。让我们在x = 10 处求值示例多项式。

事实上,在所有要评估的x选择中,只有最多 3 个选择在这些多项式中具有相同的评估,而所有其他选择都会有所不同。

这就是为什么如果证明者声称知道某个多项式(无论其度数有多大),而验证者也知道的话,他们可以遵循一个简单的协议:

  • 验证者为x选择一个随机值,并在本地评估多项式
  • 验证者将x提供给证明者,并要求其计算相关多项式
  • 证明者在x 处评估多项式,并将结果提供给验证者
  • 验证者检查本地结果是否等于证明者的结果,如果是,则该语句具有很高的置信度

例如,如果我们考虑x的整数范围从 1 到 1⁰⁷⁷,则评估不同的点数为 1⁰⁷⁷ — d 。因此, x意外“击中”任何d个共享点的概率等于(这被认为是可以忽略不计的):

注意:与低效的位校验协议相比,新协议仅需要一轮,并且对该声明具有压倒性的信心(假设 d 足够小于范围的上限,则几乎为 100%)。

这就是为什么多项式是 Beam -SNARK的核心,尽管也可能存在其他证明媒介。

原文:https://medium.com/@Moonchain_com/why-and-how-beam-snark-works-94f703cf1413

Polygon zkEVM bridge技术文档

1. 引言

区块链互操作性是指链A与链B交互数据的能力。近年来区块链生态快速扩张,出现了大量具有不同属性的区块链网络,互操作性是区块链设计时的一个重要考虑指标。不具有互操作性,网络具有孤立于更大生态的风险,为此,激励了项目方研究和开发互操作性解决方案。每种互操作性解决方案具有不同的权衡和底层技术。本文由Polygon团队提供的解决方案,为Polygon zkEVM L2网络提供了原生的互操作性。

bridge为基础设施元素,允许L1与L2之间进行资产迁移和通信。从用户角度来看,bridge可在不改变资产数量或资产功能的情况下,将资产由网络A转移至网络B;bridge也可以在网络间发送data payload(即跨链消息传递)。

Polygon zkEVM这样的L2 rollups,其L2 State Transitions和交易的数据可用性 均由L1合约来保证,因此,若正确设计L2架构,可仅依赖于合约逻辑来同步bridge的两端,而不需要可信的链下relayer来跨网络同步bridge两端。需注意的是,本bridge方案必须在L2层包含相应的设计

如图1所示,bridging interface为部署在L1和L2网络上的bridge合约,用户可用于:

  1. bridge assets(1):在“origin”网络lock某资产,在“destination”网络的bridge合约中claim时,会mint出该资产的representative token。
  2. bridge assets的逆操作(2):burn某资产的representative token,然后在“origin”网络中unlock其原始资产。
  3. 跨链通讯channel(3):在L1和L2之间相互发送data payload。

2. Exit Merkle trees

bridge中包含了名为Global Exit Merkle Tree(GEMT)的默克尔树。在GEMT树中,每个叶子节点表示了特定网络的Exit Merkle Tree(EMT).GEMT树中仅包含了2个叶子节点,一个对应为L1 EMT root,另一个对应为L2 EMT root。GEMT树的结构如图2所示:

GEMT为固定只有2个叶子节点的常规默克尔树,而EMT为append only sparse Merkle Trees(SMT)且具有固定的depth(Polygon zkEVM中设计depth为32)。SMT为大量使用的默克尔树,可在链上高效使用——详情见附录A。

特定网络EMT的每个叶子节点,表示了从该网络往外 bridge某资产(或某资产的representative token)或 发送某消息 的意图。EMT每个叶子节点为如下参数的abi encoded packed structurekeccak256哈希值

  1. uint8 leafType:0表示asset,1表示message。
  2. int32 originNetwork:为原始资产所属的Origin Network ID。
  3. address originAddress:若leafType=0,则为Origin network token address,其中“0x000…0000”保留为ether token address;若leafType=1,则为message的msg.sender。
  4. uint32 destinationNetwork:为bridging的destination网络ID。
  5. address destinationAddress:为目标网络中接收bridged asset的收款方地址。
  6. uint256 amount:bridge的token或ether数量。
  7. bytes32 metadataHash:为metadata哈希值。metadata将包含所转移资产信息或所转移message payload信息。

一旦某leaf添加到EMT中,将计算新的EMT root,以及新的GEMT root。GEMT root将在网络间同步,使得可在对方网络中证明leaf inclusion,并完成bridge操作。

3. 合约架构

大多数bridge架构都使用在双方网络上的智能合约来实现。但是,为同步二者的GEMT,有一部分bridge逻辑必须与L2 State管理架构进行集成。因此,为理解本brIdge方案,还需要考虑L2 State管理中涉及到的链下角色——如Sequencer、Aggregator以及PolygonZkEVM.sol合约。
此外,bridge架构中还包含以下元素:

  1. PolygonZkEVMBridge.sol合约:为bridging interface,允许用户与该bridge进行交互,并进行bridgeAsset/bridgeMessage/claimAsset/claimMessage等操作。每个网络都有一个PolygonZkEVMBridge.sol合约,并管理相应的EMT。
  2. PolygonZkEVMGlobalExitRoot.sol合约:管理GEMT树,充当GEMT树的历史存储库,具体为:
    2.1 存储GEMT树,
    2.2 每次由PolygonZkEVM.sol合约更新新的EMT(实际为更新L2 EMT)时,会计算新的GEMT root,
    2.3 每次由L1的PolygonZkEVMBridge.sol合约更新新的EMT(实际为更新L1 EMT)时,会计算新的GEMT root。
  3. PolygonZkEVMGlobalExitRootL2.sol合约:为一种特殊的合约,用于跨网络同步GEMT和L2 EMT roots:
    3.1 该合约中有storage slots来存储GEMT roots以及L2 EMT root。
    3.2 该合约的特殊性在于:底层的zero-knowledge proving/verification系统可直接访问其storage slots,以确保由L1同步到L2(L1->L2)的GEMT的有效性,以及有L2同步到L1(L2->L1)的L2 EMT的有效性。

3.1 bridging数据流


图3展示了详细的bridge架构,以及为实现bridge操作的finality,双方网络是如何交互的。具体分为2种bridge操作:

  1. 由L1->L2的bridge操作
  2. 由L2->L1的bridge操作

3.1.1 由L1->L2的bridge操作


由L1->L2的bridge操作的基本流程为:

  • (1)用户调用L1 PolygonZkEVMBridge.sol合约的bridgeAsset/bridgeMessage函数。取决于具体的asset类型,该函数的内部实现将有所不同。若该bridge请求有效,则合约将根据该请求的属性来填充新的L1 EMT leaf,将该叶子节点填充到EMT树中,并计算新的L1 EMT root。
  • (2)在bridgeAsset/bridgeMessage同一L1交易中,L1 PolygonZkEVMBridge.sol合约会调用L1 PolygonZkEVMGlobalExitRoot.sol合约来更新新的L1 EMT root,并计算新的GEMT root。
  • (3)L2 Sequencer将从 L1 PolygonZkEVMGlobalExitRoot.sol合约中获取新的GEMT root。
  • (4)在transaction batch execution之初,L2 Sequencer会将新的GEMT root存入 L2 PolygonZkEVMGlobalExitRootL2.sol合约的特殊storage slots中,允许L2用户访问。
  • (5)&(6)为完成bridging流程,用户必须调用L2 PolygonZkEVMBridge.sol合约的claimAsset/claimMessage函数,并提供之前已添加到EMT的节点的Merkle inclusion proof。L2 PolygonZkEVMBridge.sol合约 将从 L2 PolygonZkEVMGlobalExitRootL2.sol合约中获取GEMT root,并验证该inclusion proof的有效性。若该inclusion proof有效,则取决于所bridge的资产类型,L2 PolygonZkEVMBridge.sol合约将完成相应的bridging流程。若该inclusion proof无效,则该交易将被revert。

3.1.2 由L2->L1的bridge操作


由L2->L1的bridge操作的基本流程为:

  • (1)用户调用L2 PolygonZkEVMBridge.sol合约的bridgeAsset/bridgeMessage函数。取决于具体的asset类型,该函数的内部实现将有所不同。若该bridge请求有效,则合约将根据该请求的属性来填充新的L2 EMT leaf,将该叶子节点填充到EMT树中,并计算新的L2 EMT root。
  • (2)在bridgeAsset/bridgeMessage同一L2交易中,L2 PolygonZkEVMBridge.sol合约会调用L2 PolygonZkEVMGlobalExitRootL2.sol合约来更新新的L2 EMT root ,并计算新的GEMT root 。
  • (3)L2 Aggregator将为 包含了 该L2 bridge交易在内 的sequence of batches的execution生成相应的计算完整性Zero-Knowledge proof。通过该execution,可从L2 State中获得新的L2 EMT.
  • (4)L2 Aggregator会将新的L2 EMT以及相应的ZKP证明提交到 L1 PolygonZkEVM.sol合约。
  • (5)L1 PolygonZkEVM.sol合约会验证该ZKP证明的有效性,若有效,L1 PolygonZkEVM.sol合约 会调用 L1 PolygonZkEVMGlobalExitRoot.sol来更新新的L2 EMT root,并计算新的GEMT root。
  • (6)&(7)为完成bridging流程,用户必须调用L1 PolygonZkEVMBridge.sol合约的claimAsset/claimMessage函数,并提供之前已添加到EMT的节点的Merkle inclusion proof。L1 PolygonZkEVMBridge.sol合约 将从 L1 PolygonZkEVMGlobalExitRootL2.sol合约中获取GEMT root,并验证该inclusion proof的有效性。若该inclusion proof有效,则取决于所bridge的资产类型,L1 PolygonZkEVMBridge.sol合约将完成相应的bridging流程。若该inclusion proof无效,则该交易将被revert。

3.2 L1/L2 PolygonZkEVMBridge.sol合约

PolygonZkEVMBridge.sol合约为特定网络用户的bridging interface,因此在每个网络都有一个PolygonZkEVMBridge.sol合约。

PolygonZkEVMBridge.sol合约具有:

  • 所需的storage slots,来维护每个网络的EMT
  • 所需的函数供用户交互

PolygonZkEVMBridge.sol合约目前有2种bridge函数:

  • 1)bridgeAsset函数
  • 2)bridgeMessage函数

默认L2网络的账号是没有ether来支付交易手续费的,当claiming源自L1的Asset或Message时,调用L2 bridge合约claiming函数的 L2 claiming交易可以不支付gas费,由polygon zkEVM协议来资助

PolygonZkEVMBridge.sol合约目前有2种claiming函数

  • 1)claimAsset函数
  • 2)claimMessage函数

3.2.1 bridgeAsset函数

bridgeAsset函数用于向另一网络转移资产:

function bridgeAsset(
    uint32 destinationNetwork,
     address destinationAddress,
     uint256 amount,
     address token,
     bool forceUpdateGlobalExitRoot,
     bytes calldata permitData
)

bridgeAsset函数参数有:

  • token:为原始网络的ERC20 token地址,若为“0x0000…0000”,则意味着用户想要转移ether。
  • destinationNetwork:为目标网络的网络ID,必须不同于 调用本函数的所属网络ID,否则交易将被rever。
  • destinationAddress:目标网络接收所bridge token的收款方地址。
  • amount:bridge的token数量。
  • permitData:为具有EIP-2612 Permit扩展的ERC-20 token的 已签名permit data,用于改变某账号的ERC-20 allowance,并允许bridge合约将所bridged token转移给自身。


所bridge的资产类型有3种,对应的bridgeAsset有3条可能的执行流:

  • (1)所bridged asset为ether。

    • 对应bridgeAsset函数的token参数为“0x0000…0000”。
    • 交易的msg.value必须匹配amount参数。
    • 为完成bridge操作,相应的ether数量将lock在bridge合约中。注意L1和L2的ether将以相同的方式来处理,按1:1兑换。且ether为L1和L2网络的原生token,用于支付gas费。
    • 由于ehter源自L1,相应leaf中的originNetwork参数将设置为L1网络ID。
  • (2)所bridged asset为源自另一网络ERC20 token的representative ERC-20 token。

    • Representative ERC-20 tokens由PolygonZkEVMBridge.sol管理——负责mint和burn。
    • bridge合约中有名为wrappedTokenToTokenInfo的map,为记录部署在本网络的representative ERC-20 token contracts list。
    • 对于所部署的每个representative token contract,wrappedTokenToTokenInfo map会以该representative token合约地址为key,相应的value为TokenInformation结构体:
      // Wrapped Token information struct
       struct TokenInformation {
       uint32 originNetwork;
       address originTokenAddress;
       }
    • 对应bridgeAsset函数的token参数为wrappedTokenToTokenInfo map中的某key,则意味着所bridged token为源自另一网络ERC-20 token的representative ERC-20 token。
    • 为完成bridge操作,对应amount参数相应数量的token将被burn,bridge合约无需用户许可,有权burn相应的token。leaf中的originAddress和originNetwork参数将从wrappedTokenToTokenInfo map相应value中获取。
  • (3)所bridged asset为源自本网络的ERC-20 token。

    • 为完成bridge操作,对应amount参数相应数量的token将lock在bridge合约中。
    • 为让bridge合约能将相应数量的token转移给自身,bridge合约必须具有不少于用户所bridge token数量的allowance。
    • 若该token合约支持EIP-2612 permit扩展,相应的allowance可在同一笔交易中实现——对应有signed permitData参数。
    • leaf中的originAddress和originNetwork参数分别为当前网络ID和ERC-20 token合约地址。
    • leaf中的meatadataHash参数计算方式为
      metadataHash = keccak256(
        abi.encode(
            IERC20MetadataUpgradeable(token).name(),
            IERC20MetadataUpgradeable(token).symbol(),
            IERC20MetadataUpgradeable(token).decimals()
        )
      )

      对应在bridgeAsset函数中的metadata具体表示为:

      // Encode metadata
      metadata = abi.encode(
        _safeName(token),
        _safeSymbol(token),
        _safeDecimals(token)
      );

      最后的仔细步骤则是相同的,与资产类型无关。剩余的leaf参数有:

  • leafType参数:设置为0,表示资产。

  • destinationNetwork和destinationAddress参数:根据调用bridgeAsset函数的相应参数设置。

bridgeAsset流程中:

  • 会释放包含了new leaf所有信息的BridgeEvent事件
  • 该new leaf将添加到EMT中
  • 为更新该new EMT root,会调用GEMT合约。

3.2.2 bridgeMessage函数

bridgeMessage函数用于向另一网络转移消息:

function bridgeMessage(
    uint32 destinationNetwork,
     address destinationAddress,
     bool forceUpdateGlobalExitRoot,
     bytes calldata metadata
)

bridgeMessage函数的参数有:

  • destinationNetwork:为目标网络的网络ID,必须不同于调用本函数所在的网络ID,否则交易将被revert。
  • destinationAddress:为目标网络接收bridged message的接收地址。
  • forceUpdateGlobalExitRoot:标记是否更新新的global exit root。
  • metadata:为Message payload。

bridgeMessage函数将:

  • 直接释放BridgeEvent事件
  • 向EMT中添加new leaf
  • 与bridgeAsset函数类似,调用GEMT合约更新new EMT root

bridgeMessage函数与bridgeAsset函数的主要差异在于:

  • 所创建的leaf中的leafType参数为1
  • leaf中的orginAddress和metadataHash参数分别为msg.sender值和message payload的哈希值。
  • 用户在bridge message的同时,也可bridge ether。具体bridged ether的数量添加在bridgeMeesage函数调用交易的msg.value中,在目标网络上接收消息的同时,可destinationAddress.call{value: amount}获得相应的ether。

3.2.3 claimAsset函数

claimAsset函数用于claim源自另一网络bridge来的资产:

function claimAsset(
    bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,
     uint32 index,
     bytes32 mainnetExitRoot,
     bytes32 rollupExitRoot,
     uint32 originNetwork,
     address originTokenAddress,
     uint32 destinationNetwork,
     address destinationAddress,
     uint256 amount,
     bytes calldata metadata
)

claimAsset函数参数有:

  • smtProof:为Merkle proof,即为验证该leaf所需的sibling nodes array。
  • index:为leaf index。
  • mainnetExitRoot:为包含该leaf的L1 EMT root。
  • rollupExitRoot:为包含该leaf的L2 EMT root。
  • originNetwork:为所bridge资产所属的原始网络ID。
  • originTokenAddress:为原始网络的ERC-20 token地址,若为0x0000…0000,则表示claIm的为ether资产。
  • destinationNetwork:为目标网络ID,即为调用claimAsset函数所属的网络ID。
  • destinationAddress:为接收bridged token的收款方地址。
  • amount:所claim的token数量。
  • metadata:
    • 若claim的token为ether 或 为调用claimAsset函数所属网络的ERC-20 token,则metatdata值为0(metadata参数设置为0x)。
    • 若bridgeAsset时,bridge的为orginNetwork的ERC-20 token时,提供metadata,供目标网络上claimAsset时,wrap相应的representative token。

// 以上数据参数,通过bridge service服务api提供

// Encode metadata,bridgeAsset本网络ERC-20 token
    metadata = abi.encode( 
    _safeName(token),
    _safeSymbol(token),
    _safeDecimals(token)
);

// claimAsset时,基于metadata构建相应的wrap token
// Get ERC20 metadata
(
    string memory name,
    string memory symbol,
    uint8 decimals
) = abi.decode(metadata, (string, string, uint8));

// Create a new wrapped erc20 using create2
TokenWrapped newWrappedToken = (new TokenWrapped){
    salt: tokenInfoHash
}(name, symbol, decimals);

claimAsset函数会根据用户提供的参数来验证相应leaf的有效性。
为避免重放攻击,需确保指定leaf仅能成功验证一次。PolygonZkEVMBridge.sol合约具有claimedBitMap map来存储每个已成功验证leaf index的nullifier bit,具体如图5所示:

为优化storage slots usage,claimedBitMap map中的每个条目会hold 256 nullifier bits for 256 already verified leaves。
认定 某指定leaf的merkle proof是有效的,需满足以下条件:

  • claimedBitMap map中该leaf index的nullifier bit必须未设置。
  • 该leaf中的destinationNetwork参数必须 与 调用claimAsset函数所属网络ID 一致。
  • 对mainnetExitRoot参数和rollupExitRoot参数哈希获得的GEMT root结果,必须已存在于PolygonZkEVMGlobalExitRoot.sol 合约中。
  • 该merkle proof必须有效,即可生成期待的GEMT root。

若该leaf验证成功,与该leaf index相应的claimedBitMap map中的bit将被nullified,后续的流程如图6所示:

与bridgeAsset一致,claimAsset根据资产类型不同,有3种可能的执行流程:

  • (1)所claimed asset为ether:
    • originTokenAddress参数为“0x0000…0000”
    • amount参数对应数量的ether将发送到destinationAddress参数对应的地址账号中。
    • 由于ether无法minted on demand,L2 PolygonZkEVMBridge.sol 合约中具有preminted 100000000000 ether(1000亿个ether)作为ether bridging liquidity。由于假设所有的L2 ether都源自L1,因此,L1 PolygonZkEVMBridge.sol 合约中无需预置ether balance,L2中的每个ether wei都有a backing ether wei blocked in L1 contract。注意,L2 PolygonZkEVMBridge.sol 合约中 preminted liquidity并不会ether有任何通胀影响。【不过目前genesis中,L2 PolygonZkEVMBridge.sol 合约中preminted ether数为20亿个。】
  • (2)所claimed asset为源自本网络的ERC-20 token
    • originNetwork参数对应 调用claimAsset函数所属网络ID。
    • 意味着所claimed asset源自本网络,且之前已在PolygonZkEVMBridge.sol合约中锁定。
    • amount对应发送到destinationAddress参数对应地址账号中的相应ERC-20 token数量。
  • (3)所claimed asset为源自另一网络ERC-20 token的representative ERC-20 token:
    • PolygonZkEVMBridge.sol合约中有tokenInfoToWrappedToken map,该map中存储了部署在本网络的representative ERC-20 token合约地址。部署的representative ERC-20 token合约采用create2 opcode,相应的salt为tokenInfoToWrappedToken map的key值。该salt值根据originNetwork和originTokenAddress参数计算而来:
      // The tokens is not from this network
      // Create a wrapper for the token if not exist yet
      bytes32 tokenInfoHash = keccak256(
        abi.encodePacked(originNetwork, originTokenAddress)
      );
    • bridge合约会检查所claimed asset的representative ERC-20 token合约是否已存在tokenInfoToWrappedToken map中:
      • 若存在,则说明已部署该representative ERC-20 token合约,可mint对应amount参数数量的token到destinationAddress参数对应的账号中。
      • 若不存在,则需使用create2 opcode以及之前计算的salt 来部署新的representative ERC-20 token合约。使用create2 opcode和指定的salt,可确定性的绑定 representative token的合约地址 与 origin network的origin token合约地址。部署成功后,可mint对应amount参数数量的token到destinationAddress参数对应的账号中,同时:
        • 会释放NewWrappedToken事件。
        • 会在tokenInfoToWrappedToken map和wrappedTokenToTokenInfo map中添加新representative ERC-20 token合约的新条目。

最终,无论是claim的是哪种资产,都会释放ClaimEvent事件。

3.2.4 claimMessage函数

claimMessage函数用于claim源自其它网络的message:

function claimMessage(
bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof,
     uint32 index,
     bytes32 mainnetExitRoot,
     bytes32 rollupExitRoot,
     uint32 originNetwork,
     address originAddress,
     uint32 destinationNetwork,
     address destinationAddress,
     uint256 amount,
     bytes calldata metadata
)

与claimAsset函数类似,claimMessage会验证用户给定的leaf,由于二者的leaf格式是一样的,因此这2个函数的参数也是一样的。
与claimAsset函数一样,若leaf验证通过,通过设置相应leaf index对应在claimdBitMap map中的bit,来将相应leaf index nullified。
然后哦,底层会调用destinationAddress参数:

// Execute message
// Transfer ether
/* solhint-disable avoid-low-level-calls */
(bool success, ) = destinationAddress.call{value: amount}(
    abi.encodeCall(
        IBridgeMessageReceiver.onMessageReceived,
        (originAddress, originNetwork, metadata)
    )
);

可看出,为调用onMessageReceived函数设置了originAddress, originNetwork, metadata参数,且若message中包含了ether,相应的call value设置为amount参数。其中metadata参数为message payload。
注意,messaging service可用于将ether转移给Externally owned accounts(EOAs),但是,EOAs无法解析消息,因此message payload对其不可用。

最终,若message发送成功,则会释放ClaimEvent事件。

3.3 L2 PolygonZkEVMGlobalExitRoot.sol合约

PolygonZkEVMGlobalExitRoot.sol合约为L1合约,可计算和存储每个new GEMT root。为确保所添加的每个leaf在未来都可被验证,需要存储每个GEMT root。名为globalExitRootMap的map用来存储所有已计算的GEMT roots。

L1 PolygonZkEVMBridge.sol合约在验证leaf时,会从globalExitRootMap map中获取GEMT roots。

L1 PolygonZkEVMGlobalExitRoot.sol合约中updateExitRoot函数用于更新EMT roots并计算新的GEMT root,updateExitRoot函数会 由L1 PolygonZkEVM.sol合约 或 由L1 PolygonZkEVMBridge.sol合约 调用:

  • 若由L1 PolygonZkEVM.sol合约调用updateExitRoot函数,则将更新L2 EMT root。
  • 若由L1 PolygonZkEVMBridge.sol合约调用updateExitRoot函数,则将更新L1 EMT root。
function updateExitRoot(bytes32 newRoot) external

  • 每个L2 state transition均由L1 PolygonZkEVM.sol合约固化(通过验证Aggregator提交的ZKP证明),通过调用L1 PolygonZkEVMGlobalExitRoot.sol合约的updateExitRoot函数,将更新new L2 EMT root。
  • 当有new leaf添加到L1 PolygonZkEVMBridge.sol合约的L1 EMT中时,通过调用L1 PolygonZkEVMGlobalExitRoot.sol合约的updateExitRoot函数,将更新new L1 EMT root。

最终,都会释放UpdateGlobalExitRoot事件。

3.4 L2 PolygonZkEVMGlobalExitRootL2.sol合约

L2 PolygonZkEVMGlobalExitRootL2.sol 合约 为部署在L2上的“特殊”合约。
【v1.1版本的bridge文档与当前的实现有出入】
Aggregator zkEVM node软件在执行完transactions batches时,可直接访问L2 PolygonZkEVMGlobalExitRootL2.sol 合约的lastRollupExitRoot storage slots。lastRollupExitRoot storage slots中存储的为L2 EMT root。
随后,该L2 EMT root会和L2 State transition proof一起,提交到L1 PolygonZkEVM.sol合约中。若该proof验证通过,则会更新L1 PolygonZkEVMGlobalExitRoot.sol合约中的new L2 EMT root,并计算new GEMT,从而使得L1 PolygonZkEVMBridge.sol合约可获得有效的GEMT roots来验证包含在aggregated batches中的user claim transactions。

附录A Gas efficient append only sparse Merkle tree

sparse Merkle tree基础只是可参看:
Sparse Merkle Tree
sparse Merkle tree为具有intractable size的Merkle tree,可以以有效的方式处理。假设它几乎是空的,事实上,最初它是空的。当它中的所有叶子都具有相同的零(空)值时,它被认为是空的,由于这种假设,可以通过log ⁡ 2 ( n ) \log_2(n)log
2

(n)次哈希运算来计算root,其中n nn是树上的叶子数量。请注意,而对于non-sparse tree,需要2 n − 1 2n−12n−1次哈希运算才能计算root。在计算空树根的过程中,在每个level中,所有节点都将取相同的值,因此不需要计算每个level中的所有子树。当树的特定level的节点为空时,该节点的值都被命名为Zero Hash,并将表示具有x xx个零叶子的subtree。

以3层(8个叶子)的empty sparse Merkle tree为例,相应的Zero H按时list为:




参考资料

[1] polygon zkEVM Technical Document Bridge v.1.1

原文链接:https://blog.csdn.net/mutourend/article/details/129986151

精选的 zkEVM 资源、库、工具等精选列表

Awesome zkEVM Awesome

zkEVM is a Fully EVM equivalent and zk friendly virtual machine.

Contents

Article - Video

Rollup

zkEVM

zk-hardware

Zero-Knowledge-Proofs

zk-SNARK

Plonk

Halo2

Resources - libraries, tools

Early Rollup

Scroll and Appliedzkp(PSE)

Polygon Hermez

Polygon Zero

zkSync

StarkWare

Zero-Knowledge-Proofs

Halo2

zkp Acceleration

Different Solutions

Native zkEVM

Compiler-Based zkEVM

Transpiler-Based zkEVM

Other

Contributing

Contributions are very welcome!

Please have a look at contributing.md for guidelines.

英文原文:https://github.com/LuozhuZhang/awesome-zkevm

Polygon zkEVM节点代码解析

1. 引言

源代码:https://github.com/0xPolygonHermez/zkevm-node (Go语言)

Polygon zkEVM节点提供的主要服务模块有:

  • 1)JSON-RPC服务
  • 2)Sequencer服务
  • 3)Aggregator服务
  • 4)Synchronizer服务
  • 5)Broadcast服务

2. JSON-RPC服务

以太坊JSON-RPC接口Polygon zkEVM中的JSON-RPC接口 对比情况为:

序号 RPC接口名 以太坊 Hermez 2.0 备注
1 GetBlockByHash
2 GetBlockByNumber
3 GetBlockTransactionCountByHash
4 GetBlockTransactionCountByNumber
5 getUncleCountByBlockHash
6 getUncleCountByBlockNumber
7 ChainId
8 Syncing
9 Coinbase X
10 Accounts X
11 BlockNumber
12 Call
13 EstimateGas
14 CreateAccessList X EIP-2930:新交易类型,需以更贵的方式访问清单(地址或storage keys)外的内容。
15 GasPrice
16 MaxPriorityFeePerGas X
17 FeeHistory X
18 NewFilter
19 NewBlockFilter
20 NewPendingTransactionFilter
21 UninstallFilter
22 GetFilterChanges
23 GetFilterLogs
24 GetLogs
25 Mining X
26 Hashrate X
27 GetWork X
28 SubmitWork X
29 SubmitHashrate X
30 Sign X
31 SignTransaction X
32 GetBalance
33 GetStorageAt
34 GetTransactionCount
35 GetCode
36 GetProof X
37 SendTransaction X
38 SendRawTransaction
39 GetTransactionByHash
40 GetTransactionByBlockHashAndIndex
41 GetTransactionByBlockNumberAndIndex
42 GetTransactionReceipt
43 GetCompilers
44 GetUncleByBlockHashAndIndex
45 GetUncleByBlockNumberAndIndex
46 ProtocolVersion

Hermez 2.0(zkEVM)除实现了以上与以太坊兼容的RPC接口之外,还额外实现了一些与state交互、与pool交互的接口

// jsonRPCTxPool contains the methods required to interact with the tx pool.
type jsonRPCTxPool interface {
    AddTx(ctx context.Context, tx types.Transaction) error
    GetPendingTxs(ctx context.Context, isClaims bool, limit uint64) ([]pool.Transaction, error)
    GetGasPrice(ctx context.Context) (uint64, error)
    GetPendingTxHashesSince(ctx context.Context, since time.Time) ([]common.Hash, error)
}

// gasPriceEstimator contains the methods required to interact with gas price estimator
type gasPriceEstimator interface {
    GetAvgGasPrice(ctx context.Context) (*big.Int, error)
}

// stateInterface gathers the methods required to interact with the state.
type stateInterface interface {
    BeginStateTransaction(ctx context.Context) (pgx.Tx, error)

    GetLastConsolidatedL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error)
    GetTransactionByHash(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*types.Transaction, error)
    GetTransactionReceipt(ctx context.Context, transactionHash common.Hash, dbTx pgx.Tx) (*types.Receipt, error)
    GetLastL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error)
    GetLastL2Block(ctx context.Context, dbTx pgx.Tx) (*types.Block, error)
    GetLastL2BlockHeader(ctx context.Context, dbTx pgx.Tx) (*types.Header, error)
    EstimateGas(transaction *types.Transaction, senderAddress common.Address) (uint64, error)
    GetBalance(ctx context.Context, address common.Address, blockNumber uint64, dbTx pgx.Tx) (*big.Int, error)
    GetL2BlockByHash(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (*types.Block, error)
    GetL2BlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*types.Block, error)
    GetCode(ctx context.Context, address common.Address, blockNumber uint64, dbTx pgx.Tx) ([]byte, error)
    GetStorageAt(ctx context.Context, address common.Address, position *big.Int, blockNumber uint64, dbTx pgx.Tx) (*big.Int, error)
    GetSyncingInfo(ctx context.Context, dbTx pgx.Tx) (state.SyncingInfo, error)
    GetTransactionByL2BlockHashAndIndex(ctx context.Context, blockHash common.Hash, index uint64, dbTx pgx.Tx) (*types.Transaction, error)
    GetTransactionByL2BlockNumberAndIndex(ctx context.Context, blockNumber uint64, index uint64, dbTx pgx.Tx) (*types.Transaction, error)
    GetNonce(ctx context.Context, address common.Address, blockNumber uint64, dbTx pgx.Tx) (uint64, error)
    GetL2BlockHeaderByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*types.Header, error)
    GetL2BlockTransactionCountByHash(ctx context.Context, hash common.Hash, dbTx pgx.Tx) (uint64, error)
    GetL2BlockTransactionCountByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (uint64, error)
    GetLogs(ctx context.Context, fromBlock uint64, toBlock uint64, addresses []common.Address, topics [][]common.Hash, blockHash *common.Hash, since *time.Time, dbTx pgx.Tx) ([]*types.Log, error)
    GetL2BlockHashesSince(ctx context.Context, since time.Time, dbTx pgx.Tx) ([]common.Hash, error)
    DebugTransaction(ctx context.Context, transactionHash common.Hash, tracer string) (*runtime.ExecutionResult, error)
    ProcessUnsignedTransaction(ctx context.Context, tx *types.Transaction, senderAddress common.Address, blockNumber uint64, dbTx pgx.Tx) *runtime.ExecutionResult
    IsL2BlockConsolidated(ctx context.Context, blockNumber int, dbTx pgx.Tx) (bool, error)
    IsL2BlockVirtualized(ctx context.Context, blockNumber int, dbTx pgx.Tx) (bool, error)
}

type storageInterface interface {
    NewLogFilter(filter LogFilter) (uint64, error)
    NewBlockFilter() (uint64, error)
    NewPendingTransactionFilter() (uint64, error)
    GetFilter(filterID uint64) (*Filter, error)
    UpdateFilterLastPoll(filterID uint64) error
    UninstallFilter(filterID uint64) (bool, error)
}

3. Sequencer服务



当前代码库中,暂未实现permissionless sequencer功能,ProofOfEfficiency.sol合约中也暂未实现registerSequencer等接口。

参考资料

[1] Ethereum JSON-RPC Specification
[2] PoE
[3] zkProver debugging
[4] Hermez 1.5 - Merkle Tree spec
[5] PoE - 1.5

附录:Polygon Hermez 2.0 zkEVM系列博客

转载:https://blog.csdn.net/mutourend/article/details/126409344