以太坊智能合约版本升级的核心方法

2019-12-29

合适的升к级方法

现在让我们来看看一些更复杂、更合适的智能合约升级方法。

继承的存储可升级性

这种技术使用三种不同的合约:代理合约来委托调用●并充当永久存储;&逻辑合约将处理数据;还有存储合约。代理合约和☺☻逻辑合约都继承自存储合约,因此它们的存储引用是对齐的。


当逻辑合约更新时,我们只需要更改代理≌合约所指向的位置即可使用仅管理员功能。由于代理和逻辑协定具有相同的存储指针,因此无需进行外部调用即可查看和修改数据。

不幸的是,这种方法也有其自身的陷阱。由于代理合约和存储合约都♥是永恒的,因此,如果在任何一个合约中发现错误或漏洞,都无法修复。 因此务必仔细考虑您的代理和存储结构。

非结构化存储可升级性

非结构化存储可能是当前最大的可升级性方法,它使我们能够利用存储中۩状态变量的布局。此方法仅需要两个合约-代理合约和实施合约-实ω施合约包含数据和γ存储。

该技术的工作原理是将可升级性所需的数据保存▐在存储中的固定位置,以防止被新数据覆盖。我们可以使用SLOAD和SSTORE操作码进△行汇编。由于存储插槽只是从0x0开始递增,因此我们使用很高的存储插槽来防止覆盖 我们可Ⅹ以通过对常量变量进行散列来生成存储槽。 由于恒定状态变量不会占用存储空间,因此我们不必担心它会被覆盖。

bytes32 private cξonstant implementationPosition =
keccak256("org.zeppelinos.proxy.implementation");

由于代理不再从存储合约继承而来,因此我们现在也可以更新存▒储,从而防止存储错误/漏洞变成灾难性的。 但是在升级实施合约时,我们必须继承以前的合约。由于不需要更改实施合约,因此该方法甚至可以与现有合约一起使用。


尽管这可能是当前可升级性最好的方法,但也有不少批评。代理所有者拥有巨大的权力,并且需要一定程度的信任。℃对于更复杂的系统▨,这可能也不是合适的解决方案。

升级依赖于构造函数的合约

当使用依赖于构造函数的合约来设置一些初始状态时,与代理工作并不太简单。由于构造函数只运行一次,而代理不知道逻辑合约构造函数◆中设置的值,因此我们需要一种方法在代理中初始化其中的一些值。

创建逻辑合约后,EVM会丢弃构造⿳函数,因此我们不⊙能简单地重用代码。相反,我们必须采取独特的方法来解决此问题。

初始化Ж函数

一种可能╤的替代方法是在常规函数中使用构造函数代码。我们只需确保这⌒个函数(我们将调用初始化函数)只能运行一次。

contrac╩t ∞Initializable ◎{

 ц /**
  ∕ * ō@dev IndicaШtes that the contract has been initialized.
   */
&n۞bsp; bool private iniаtialized;

  /**
   * @dev Indicates that the contract is in the process of bein⊙g initiali≠zed.
  &nb☼sp;*/
  bool priva卐te iↃnitializing;

  /**
 ψ  * @dev Modifier to use in the initializer function of a contract.
   */
&Йnbsp; modifier initializer() {
  Ⅻ  require(initiЯalizing || !initialized, "Contract instance has already been initialized");

    bool wasInitializing = initializing;
    initializing = true;
&n|bsp;   initialized = tru∶e;
&n々bsp;   _;

    initializing = wasInitializing;
  }
}

在┏使用初始值设定项函数时,必须打起十二分精神。考虑逻辑合约继承的基本合约也很重要。这部分特别复杂,因为Solidity也支▓持多重继承。

结论

确ζ保智能〧合约是可升级的,并仔细考虑可升级过程,这两点都很重要。虽然这并不是一个关于智能合约可升级性的选项的详尽列表,但这应该是关于这个主题๑的适当指南。

来源: 区块链研究实验室 作者:链※三丰


&#x‖|f012f; 分享

相关文章