首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >什么样的设计模式适合于Ethereum智能契约中的数据结构修改?

什么样的设计模式适合于Ethereum智能契约中的数据结构修改?
EN

Ethereum用户
提问于 2016-02-08 08:42:58
回答 4查看 2.4K关注 0票数 16

我期待听到的设计模式,人们已经实现了Ethereum智能合同,以允许后部署修改的数据结构。

例如,假设我有一个包含定义地址的结构的契约。我是否应该认识到,我想在地址中添加一个电子邮件地址属性。是否有任何部署前设计模式的考虑,允许我这样做。

一个更复杂的例子。如果我有一个名为“问题”和“答案”的合同的两个属性,那么我突然想要得到多个可能的答案。怎样才能作出这样的改变呢?

我的问题/关注的是,如果您通过浏览器与上述合同进行接口,您可以简单地更新前端指向的合同(post更新)。但是,如何解决跨更新部署维护任何契约数据的问题?

谢谢T

EN

回答 4

Ethereum用户

发布于 2017-12-17 11:58:25

您需要考虑以下几点:

这得从一开始就计划好。您需要考虑以下5点来设计您的智能合同:

  1. 你必须有一个好的测试策略和战术。因为更新你的智能合同的成本真的会毁了你的生活。
  2. 保持您的智能合同模块化和相当独立的规则和逻辑与数据结构。因此,如果您需要更改某些内容,您将只更改相关的合同,而不需要更改许多或所有合同。
  3. 您应该准备好拥有一个紧急停止或断路器,以便能够在任何迁移过程中停止所有操作。因为您不希望在迁移期间和以后,人们仍然可以将数据更新/插入到智能契约的旧版本。
  4. 您以前应该提供读取智能契约中的所有数据的能力。当然,您可以通过限制将所有数据读取到所有者或任何其他受信任的用户,甚至其他智能契约来进行允许的读取。您将需要阅读您的智能契约的旧版本,并插入新版本。
  5. 您将使用以下策略与您的智能契约进行通信。我从智能联系人最佳实践复制了它们:

升级中断的合同

如果发现错误或需要改进,则需要更改代码。发现一个错误是没有好处的,但是没有办法去对付它.然而,有两种最常用的基本方法。两者中比较简单的是要有一个注册合同,其中包含合同的最新版本的地址。对于合同用户来说,一个更无缝的方法是拥有一个将调用和数据转发到合同的最新版本的合同。

示例1:使用注册表契约存储合同

的最新版本

在本例中,调用不被转发,因此用户每次都应该在与其交互之前获取当前地址。

代码语言:javascript
复制
contract SomeRegister {
    address backendContract;
    address[] previousBackends;
    address owner;

    function SomeRegister() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner)
        _;
    }

    function changeBackend(address newBackend) public
    onlyOwner()
    returns (bool)
    {
        if(newBackend != backendContract) {
            previousBackends.push(backendContract);
            backendContract = newBackend;
            return true;
        }

        return false;
    }
}

这种方法有两个主要缺点:

  1. 用户必须始终查找当前地址,任何不这样做的人都有使用旧版本合同的风险。
  2. 在替换合同时,您需要仔细考虑如何处理合同数据。

另一种方法是将合同转发到合同的最新版本:

示例2:使用DELEGATECALL转发数据并调用

代码语言:javascript
复制
contract Relay {
    address public currentVersion;
    address public owner;

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    function Relay(address initAddr) {
        currentVersion = initAddr;
        owner = msg.sender; // this owner may be another contract with multisig, not a single contract owner
    }

    function changeContract(address newVersion) public
    onlyOwner()
    {
        currentVersion = newVersion;
    }

    function() {
        require(currentVersion.delegatecall(msg.data));
    }
}

这种方法避免了以前的问题,但也有自己的问题。您必须非常小心如何在本合同中存储数据。如果您的新合约的存储布局与第一个不同,则您的数据可能最终会损坏。此外,该模式的这个简单版本不能从函数返回值,只能转发它们,这限制了它的适用性。(更复杂的实现试图用内联程序集代码和返回大小的注册表来解决这个问题。)不管您的方法如何,重要的是要有一些方法来升级您的合同,否则当不可避免的bug被发现时,它们将变得不可用。

我在媒体上创建了一个标题为:Ethereum (1)的基本设计考虑:可升级的智能契约的故事

票数 4
EN

Ethereum用户

发布于 2016-04-01 18:11:12

我们也可以回到一个不同类型的解决方案(是的,我也不喜欢它)。

有一个映射(uint => StorageItem)。

  • uint是字段ID。
  • StorageItem契约将有一个字符串值和一个整数类型。该类型将允许您从字符串转换为所需的结束类型。

这里的一个缺点是,在某种程度上,稳固将支持我们想要利用的新类型。

票数 2
EN

Ethereum用户

发布于 2016-03-23 00:31:27

我认为您可以像建议的这里那样将存储保存在单独的契约中,但是结构会将数据保存在JSON (string)对象中。然后您可以进行任何需要的修改(扩展或更改模型)。

例如:

代码语言:javascript
复制
{"address": "Some Street","phone": 123456}

会变成

代码语言:javascript
复制
{"address": "Some Street","phone": 123456, "email":"someone@email.com"}

您可以处理客户端或调用契约中缺少的值。

票数 1
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/1134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档