前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >合约工厂与克隆工厂

合约工厂与克隆工厂

作者头像
Tiny熊
发布2021-07-14 15:11:31
7080
发布2021-07-14 15:11:31
举报

译文出自:登链翻译计划[1]

  • 译者:aisiji[2]
  • 校对:Tiny 熊[3]

如何简单的在合约中部署合约并且尽可能的节省 gas

工厂设计模式[4]是编程中相当常见的模式。这个想法很简单,不是直接创建对象,而是由对象(工厂)来创建对象。在Solidity[5]中,一个对象就是一智能合约[6],所以合约工厂可以为你部署新的合约。

为什么是工厂

让我们先讨论一下什么时候以及为什么你会想要一个工厂。让我们先看看什么时候不需要工厂:

  • 你只在主网上部署一次合约,然后就不再部署了。

很明显,如果你只部署一次,工厂就没有意义。那么,多次部署呢?

  • 你想跟踪所有部署的合约。
  • 你想在部署时节省 Gas。
  • 你想为用户或你自己提供一个简单的方法来部署合约。

一个简单的工厂

在最简单的情况下,你的工厂只是一个合约,它有一个函数用来部署你实际使用的合约。让我们来看一个修改过的MetaCoin[7]

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

import "./MetaCoin.sol";

contract MetaCoinFactory {
    MetaCoin[] public metaCoinAddresses;
    event MetaCoinCreated(MetaCoin metaCoin);

    address private metaCoinOwner;

    constructor(address _metaCoinOwner ) public {
        metaCoinOwner = _metaCoinOwner ;
    }

    function createMetaCoin(uint256 initialBalance) external {
        MetaCoin metaCoin = new MetaCoin(metaCoinOwner, initialBalance);

        metaCoinAddresses.push(metaCoin);
        emit MetaCoinCreated(metaCoin);
    }

    function getMetaCoins() external view returns (MetaCoin[] memory) {
        return metaCoinAddresses;
    }
}

正如你所看到的,createMetaCoin函数部署了新的MetaCoins。可以将部署所需的变量存储在工厂内(如owner)或将它们传递给部署函数(如initialBalance)。

我们还保留了一个所有已部署合约的列表,你可以通过getMetaCoins()访问。你可能想为管理已部署的合约添加更多的功能,比如寻找特定的 MetaCoin 合约,禁用一个 MetaCoin 等等。这些都是拥有一个工厂的好理由。

但这里有一个潜在的问题:高 gas 费[8]。这里就是我们可以利用克隆(Clone)的地方了...

克隆工厂

如果你总是部署同一种合约,那么不必为这些字节码浪费 gas 了。任何合约都会有几乎相同的字节码,所以我们不需要在每次部署时重复存储所有字节码。

它是如何工作的?

也许需要谢谢DELEGATECALL[9]操作码。我们只部署一次MetaCoin合约,把它作为一个执行合约,这样,就不用每次都部署新的MetaCoin合约。当我们部署新合约时,将所有的调用委托给执行合约,记住DELEGATECALL的功能,它让合约通过自己的状态来调用执行合约,这样每个合约都可以将执行合约作为库,并且拥有自己的状态。

如何使用它

有一个很好的CloneFactory[10]软件包,不过它有点过时了,如果要在最新的 Solidity 编译器中使用它,必须复制源代码并改变 pragma 设置。它安全吗?应该是的,但使用它需要自己承担风险,或者最好先进行审计(无论如何你都应该这样做)。

  1. 不能用构造变量克隆合约,所以我们第一步是创建一个新的合约MetaCoinClonable,并把所有部署变量移到一个新的initialize函数。
  2. 然后简单地继承CloneFactory
  3. 使用createClone来部署一个新的合约。
  4. 调用initialize来传递之前的构造函数变量。
代码语言:javascript
复制
// SPDX-License-Identifier: MIT
pragma solidity 0.6.11;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./CloneFactory.sol";
import "./MetaCoinClonable.sol";

contract MetaCoinCloneFactory is CloneFactory, Ownable {
    MetaCoinClonable[] public metaCoinAddresses;
    event MetaCoinCreated(MetaCoinClonable metaCoin);

    address public libraryAddress;
    address private metaCoinOwner;

    constructor(address _metaCoinOwner) public {
        metaCoinOwner = _metaCoinOwner;
    }

    function setLibraryAddress(address _libraryAddress) external onlyOwner {
        libraryAddress = _libraryAddress;
    }

    function createMetaCoin(uint256 initialBalance) external {
        MetaCoinClonable metaCoin = MetaCoinClonable(
            createClone(libraryAddress)
        );
        metaCoin.initialize(metaCoinOwner, initialBalance);

        metaCoinAddresses.push(metaCoin);
        emit MetaCoinCreated(metaCoin);
    }

    function getMetaCoins() external view returns (MetaCoinClonable[] memory) {
        return metaCoinAddresses;
    }
}

首先需要部署一个单一的 MetaCoin 实现合约,然后通过setLibraryAddress传递其地址,就这么简单。

以前部署的合约是否受到设置新库地址的影响 ?

不,这只会影响后来的部署。如果你想让旧的合约被改变,你必须让它们可升级[11]

如果代码库地址合约自毁了怎么办 ?

所有之前部署的合约都将停止工作,所以需要确保不能发生这种情况。

有什么坏处吗 ?

不多,但如果没有适当的审计,我不会把它用于大批量的合约。当前 Etherscan 代码验证功能还不能用[12],他们增加了代理支持[13],所以也许现在能用?这可能比较麻烦,如果你做成功了,请告诉我。然而,出于安全考虑,这样做并不十分重要,因为克隆的功能非常简单,相反有一个经过验证的库合约则更重要。但是,没法在 Etherscan 上的进行合约的简单交互。

简单工厂与克隆工厂 GAS 比较

让我们看看 Gas 消耗的差异。即使是我们的小型MetaCoin合约部署也已经便宜了 50%以上。你的合约越大,差异越大。而合约越大,克隆工厂的部署在成本上不会有太大变化,但普通工厂的部署会越来越贵。

Solc version: 0.6.11+commit.5ef660b1

Optimizer enabled: true

Runs: 200

Block limit: 6721975 gas

Methods

Contract

Method

Min

Max

Avg

# calls

eur (avg)

MetaCoinCloneFactory

createMetaCoin

94539

109527

95039

30

0.68

MetaCoinFactory

createMetaCoin

208441

212653

212513

30

1.53

现在开始你可以用克隆技术节省 Gas 了。现在,Gas 费又特别高,希望这篇文章对你有用。

还有试过CloneFactory吗?你能想到使用或不使用它的其他原因吗?


本翻译由 Cell Network[14] 赞助支持。

来源:https://soliditydeveloper.com/clonefactory

参考资料

[1]

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

[2]

aisiji: https://learnblockchain.cn/people/3291

[3]

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

[4]

工厂设计模式: https://en.wikipedia.org/wiki/Factory_method_pattern

[5]

Solidity: https://learnblockchain.cn/docs/solidity/

[6]

智能合约: https://learnblockchain.cn/2018/01/04/understanding-smart-contracts

[7]

MetaCoin: https://www.trufflesuite.com/boxes/metacoin

[8]

高 gas 费: https://ethereum.stackexchange.com/q/84764/33305

[9]

DELEGATECALL: https://eips.ethereum.org/EIPS/eip-7

[10]

CloneFactory: https://github.com/optionality/clone-factory

[11]

可升级: https://hackernoon.com/how-to-make-smart-contracts-upgradable-2612e771d5a2

[12]

还不能用: https://www.reddit.com/r/etherscan/comments/9uzw8i/eip1167_clonefactory_support/

[13]

代理支持: https://medium.com/etherscan-blog/and-finally-proxy-contract-support-on-etherscan-693e3da0714b

[14]

Cell Network: https://www.cellnetwork.io/?utm_souce=learnblockchain

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么是工厂
  • 一个简单的工厂
  • 克隆工厂
    • 它是如何工作的?
      • 如何使用它
      • 简单工厂与克隆工厂 GAS 比较
        • 参考资料
        相关产品与服务
        区块链
        云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档