前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探索Openzeppelin 新增的跨链功能

探索Openzeppelin 新增的跨链功能

作者头像
Tiny熊
发布2022-11-07 09:34:19
5160
发布2022-11-07 09:34:19
举报
文章被收录于专栏:深入浅出区块链技术

译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3]

Openzeppelin 合约首次增加了跨链支持,特别是目前支持以下链:

  • Polygon[4]:现在最流行的侧链之一。之前这篇文章[5]已经讨论过它。
  • Optimism[6]: 一个基于 optimistic rollup 的 Layer 2。之前在这篇文章[7]讨论过这个技术。
  • Arbitrum[8]: 另一个是基于 optimistic rollup 的 Layer 2。
  • AMB[9]: Arbitrary Message Bridge 是一个可以用来在两个链之间转发任何数据通用工具。

跨链困难是什么?

在跨链通信中到底有哪些需要考虑的事情呢?

  • 首先是发送数据问题:你可能在以太坊主网上有治理控制的合约,比如说由一个原生的 ERC-20 控制。而你希望合约能够有一些功能改变,比如说升级子链上的一个合约。那么就需要一种方法来允许主网的合约以安全的方式向子链发送数据。
  • sender 问题: 发送跨链消息的一个困难是确定交易发起者地址,因为从合约的角度来看,msg.sender实际上是一个子链上的地址。当然 msg.sender到底是什么取决于子链,但它不会是根链的实际交易者地址。
  • 访问控制问题: 跨链的另一个问题是一个地址有可能在根链和子链都存在,所以要注意一个相同地址的合约可能存在于根链和子链上。
  • 签名的重复使用:如果你在合约中允许任何签名,它们可能会被重复使用。这就是为什么你应该经常仔细检查 chainID,或者最好使用EIP-712[10],它可以处理所有复杂的安全签名。 Openzeppelin 跨链支持是如何运作 Openzeppelin 已经增加了合约,以支持在 Polygon、Optimism、Arbitrum 和 AMB 中的使用。主要接口是CrossChainEnabled.sol[11],所有支持的四个实现都基于它。另外还有一个AccessControlCrossChain.sol[12],它支持跨链下使用角色进行安全访问控制。相关的概述可以参见这里[13]。 每个链的实现都包含一个不同的机制来检索原始的跨链交易发起者,大致上看起来像这样:
代码语言:javascript
复制
function processMessageFromRoot(
    uint256, /* stateId */
    address rootMessageSender,
    bytes calldata data
  )
代码语言:javascript
复制
AMB_Bridge(bridge).messageSender()
代码语言:javascript
复制
LibArbitrumL2.crossChainSender(LibArbitrumL2.ARBSYS)
代码语言:javascript
复制
Optimism_Bridge(messenger).xDomainMessageSender()

关于完整的细节,请查看这里的合约代码[14],相应的文档在这里[15]

如何使用跨链功能 -- Polygon 为例

让我们以 Polygon 为例,深入了解一下如何实际使用 Openzeppelin 跨链功能。

我们将在根链(Root chain)和子链(child chain)上创建具有安全访问控制的合约。

1. 创建根合约

首先让我们创建一个合约,并在根链上部署。在正常情况下,通常是以太坊主网。我们可以继承FxBaseRootTunnel.sol[16]合约,并根据网络的不同传递检查点和根地址。

  • GOERLI_CHECKPOINT_MANAGER = 0x2890bA17EfE978480615e330ecB65333b880928e
  • GOERLI_FX_ROOT = 0x3d1d3E34f7fB6D26245E6640E1c50710eFFf15bA
  • MAINNET_CHECKPOINT_MANAGER = 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287
  • MAINNET_FX_ROOT = 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2
代码语言:javascript
复制
import {FxBaseRootTunnel} from
    "fx-portal/contracts/tunnel/FxBaseRootTunnel.sol";

// see left for full addresses
address constant GOERLI_CP_MANAGER = 0x2890bA17EfE978480615e...;
address constant GOERLI_FX_ROOT = 0x3d1d3E34f7fB6D26245E6640...;

contract PolygonRoot is FxBaseRootTunnel {
    bytes public latestData;

    constructor()
        FxBaseRootTunnel(GOERLI_CP_MANAGER, GOERLI_FX_ROOT) {
    }

    function _processMessageFromChild(
        bytes memory data
    ) internal override {
        latestData = data;
    }

    function sendMessageToChild(bytes memory message) public {
        _sendMessageToChild(message);
    }
}

它有两个内部函数:

  1. _processMessageFromChild: 重写(Override)函数,以便处理从子合约发来的消息。
  2. _sendMessageToChild:调用函数来向子合约发送消息。

2. 创建子合约

然后我们在子链上创建部署子合约,在我们的案例中,子链是 Polygon 网络。我们可以继承 Openzeppelin CrossChainEnabledPolygonChild.sol[17]合约,并根据网络的情况传递 FX Portal 子合约。

  • MUMBAI_FX_CHILD = 0xCf73231F28B7331BBe3124B907840A94851f9f11
  • MAINNET_FX_CHILD = 0x8397259c983751DAf40400790063935a11afa28a

也可以使用 Openzeppelin 的AccessControlCrossChain.sol[18]。只要在合约中继承它,我们就会得到通常的访问控制功能[19]以及一个新的_crossChainRoleAlias函数。

代码语言:javascript
复制
import {CrossChainEnabledPolygonChild} from
    "oz/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol";
import {AccessControlCrossChain} from
    "oz/contracts/access/AccessControlCrossChain.sol";

address constant MUMBAI_FX_CHILD = 0xCf73231F...; // see right

contract PolygonChild is
    CrossChainEnabledPolygonChild,
    AccessControlCrossChain
{
    event MessageSent(bytes message);
    uint256 public myNumber = 12;

    constructor(
        address rootParent
    ) CrossChainEnabledPolygonChild(MUMBAI_FX_CHILD) {
        _grantRole(
            _crossChainRoleAlias(DEFAULT_ADMIN_ROLE),
            rootParent
        );
    }

    function setNumberForParentChain(
        uint256 newNumber
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        myNumber = newNumber;
    }

    function _sendMessageToRoot(
        bytes memory message
    ) internal {
        emit MessageSent(message);
    }
}

在示例中,在部署时,我们将把先前部署的根合约地址传到这里,并立即授予它管理角色,但由于这实际上是一个跨链通信,它的工作方式有点不同:

  1. 当然 onlyRole 修改器不能只检查 msg.sender,它使用CrossChainEnabled.sol[20]接口来确定实际的跨链交易发起者。
  2. 而为了进一步防止与根链中的地址相同,而在子链的合约访问,我们需要区分交易发起者是直接来自 msg.sender 还是来自 CrossChain 的发起者。为此,我们使用_crossChainRoleAlias来授予角色权限。

然后我们添加一个测试函数setNumberForParentChain,只允许 CrossChain 的根合约调用。

为了完整起见,如果你想把信息发回给根,可以在 Polygon 中通过发出 MessageSent 事件来实现。

3. 获取编码数据帮助方法

这个部署是可选的,但是处于我们的测试需要,你可以添加一个额外的函数,就像这样:

代码语言:javascript
复制
function getEncodedSetNumberData(uint256 newNumber) external pure returns (bytes memory) {
    return abi.encodeWithSelector(PolygonChild.setNumberForParentChain.selector, newNumber);
}

基本上这个函数就是返回要调用函数的编码数据,如果你想调用 setNumberForParentChain 函数,你需要获得它的编码数据,你需要通过sendMessageToChild在根合约中发送这个数据。当然,在大多数环境中,你只是在使用 Web3.js 或任何你所使用的前端框架来获得编码数据。

4. 在 Remix 上测试跨链转账

好了,现在让我们把它部署到测试网,我们这里使用:

  • Goerli[21]网络作为根链,这是最新的以太坊测试网
  • Mumbai[22]:Polygon 测试网,作为子链

对比部署到正式主网,流程是相同的,只是使用的地址不同。

所以我们可以直接把这里的全部代码复制到 Remix 中:

代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import {CrossChainEnabledPolygonChild} from "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol";
import {AccessControlCrossChain} from "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControlCrossChain.sol";

import {FxBaseRootTunnel} from "https://github.com/fx-portal/contracts/blob/main/contracts/tunnel/FxBaseRootTunnel.sol";

address constant MUMBAI_FX_CHILD = 0xCf73231F28B7331BBe3124B907840A94851f9f11;
address constant GOERLI_CHECKPOINT_MANAGER = 0x2890bA17EfE978480615e330ecB65333b880928e;
address constant GOERLI_FX_ROOT = 0x3d1d3E34f7fB6D26245E6640E1c50710eFFf15bA;

address constant MAINNET_FX_CHILD = 0x8397259c983751DAf40400790063935a11afa28a;
address constant MAINNET_CHECKPOINT_MANAGER = 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287;
address constant MAINNET_FX_ROOT = 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2;

contract PolygonChild is CrossChainEnabledPolygonChild, AccessControlCrossChain {
    uint256 public myNumber;

    constructor(address rootParent) CrossChainEnabledPolygonChild(MUMBAI_FX_CHILD) {
        _grantRole(_crossChainRoleAlias(DEFAULT_ADMIN_ROLE), rootParent);
        myNumber = 12;
    }

    function setNumberForParentChain(uint256 newNumber) external onlyRole(DEFAULT_ADMIN_ROLE) {
        myNumber = newNumber;
    }

    function getEncodedSetNumberData(uint256 newNumber) external pure returns (bytes memory) {
        return abi.encodeWithSelector(PolygonChild.setNumberForParentChain.selector, newNumber);
    }
}

contract PolygonRoot is FxBaseRootTunnel {
    bytes public latestData;

    constructor() FxBaseRootTunnel(GOERLI_CHECKPOINT_MANAGER, GOERLI_FX_ROOT) {}

    function _processMessageFromChild(bytes memory data) internal override {
        latestData = data;
    }

    function sendMessageToChild(bytes memory message) public {
        _sendMessageToChild(message);
    }
}

现在你可以:

  1. 将 MetaMask 切换到 Goerli 并部署 PolygonRoot。
  2. 将 MetaMask 切换到 Mumbai,复制地址并部署 PolygonChild 作为构造函数的输入参数。
  3. 将 MetaMask 切换到 Goerli,在 PolygonRoot 上调用 setFxChildTunnel,传递子合约地址。
  4. 对你要发送的数据进行编码。例如,将setNumberForParentChain的数字设置为 42,编码后的数据是:0x21148d91000000000000000000000000000000000000000000000000000000000000002a. 最简单的方法是通过getEncodedSetNumberData帮方法来获得。
  5. 调用 sendMessageToChild 并把编码数据作为。这将启动跨链调用。这可能需要一些时间。
  6. 等待一写时间....,同时你可以在这里[23]检查 FX_CHILD 的事件或者简单地检查零地址的转账这里[24]

这些交易看起来可能让你感到困惑,但它并不奇怪。零地址是 Polygon 的一个特殊系统地址,用于提交 CrossChain 调用。

在我的测试中,直到 Polygon 上的 CrossChain 转账完成,需要 2 到 25 分钟。

跨链调用到这里就完成了,如果一切都正确,你可以切换回 Mumbai 测试网,并读取新设置的数字,它应该已经变成了 42。


本翻译由 Duet Protocol[25] 赞助支持。

原文:https://soliditydeveloper.com/openzeppelin-crosschain

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

翻译小组: https://learnblockchain.cn/people/412

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

Polygon: https://polygon.technology/

[5]

这篇文章: https://soliditydeveloper.com/deploy-to-matic

[6]

Optimism: https://www.optimism.io/

[7]

在这篇文章: https://soliditydeveloper.com/optimism

[8]

Arbitrum: https://arbitrum.io/

[9]

AMB: https://docs.tokenbridge.net/amb-bridge/about-amb-bridge

[10]

EIP-712: https://eips.ethereum.org/EIPS/eip-712

[11]

CrossChainEnabled.sol: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/crosschain/CrossChainEnabled.sol

[12]

AccessControlCrossChain.sol: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControlCrossChain.sol

[13]

这里: https://docs.openzeppelin.com/contracts/4.x/api/crosschain

[14]

这里的合约代码: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/crosschain

[15]

这里: https://docs.openzeppelin.com/contracts/4.x/api/crosschain

[16]

FxBaseRootTunnel.sol: https://github.com/fx-portal/contracts/blob/main/contracts/tunnel/FxBaseRootTunnel.sol

[17]

CrossChainEnabledPolygonChild.sol: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.6.0/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol

[18]

AccessControlCrossChain.sol: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.6.0/contracts/access/AccessControlCrossChain.sol

[19]

访问控制功能: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.6.0/contracts/access/AccessControl.sol

[20]

CrossChainEnabled.sol: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.6.0/contracts/crosschain/CrossChainEnabled.sol

[21]

Goerli: https://goerli.net/

[22]

Mumbai: https://docs.polygon.technology/docs/develop/network-details/network#mumbai-testnet

[23]

这里: https://mumbai.polygonscan.com/address/0xcf73231f28b7331bbe3124b907840a94851f9f11#events

[24]

这里: https://mumbai.polygonscan.com/address/0x0000000000000000000000000000000000000000

[25]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 跨链困难是什么?
  • 如何使用跨链功能 -- Polygon 为例
    • 1. 创建根合约
      • 2. 创建子合约
        • 3. 获取编码数据帮助方法
          • 4. 在 Remix 上测试跨链转账
            • 参考资料
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档