设计模式:智能合约的经典设计模式及解析

这篇具有很好参考价值的文章主要介绍了设计模式:智能合约的经典设计模式及解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 智能合约设计,# 智能合约,区块链

 苏泽

大家好 这里是苏泽 一个钟爱区块链技术的后端开发者

本篇专栏 ←持续记录本人自学两年走过无数弯路的智能合约学习笔记和经验总结 如果喜欢拜托三连支持~


总而言之,智能合约实现上要达到的目标是:完备的业务功能、精悍的代码逻辑、良好的模块抽象、清晰的合约结构、合理的安全检查、完备的升级方案。 

智能合约设计,# 智能合约,区块链

经典的5种设计模式

1、自毁合约

1、自毁合约:
合约自毁模式用于终止一个合约,从区块链中永久删除该合约,无法调用合约功能或记录交易。常见用例包括定时合约或必须在达到里程碑时终止的合约。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
contract SelfDesctructionContract {
   public address owner;
   public string someValue;
   modifier ownerRestricted {
      require(owner == msg.sender);
      _;
   } 
   // constructor
   function SelfDesctructionContract() {
      owner = msg.sender;
   }
   // a simple setter function
   function setSomeValue(string value){
      someValue = value;
   } 
   // you can call it anything you want
   function destroyContract() ownerRestricted {
     suicide(owner);
   }
}

正如你所看到的, destroyContract()方法负责销毁合约。

请注意,我们使用自定义的ownerRestricted修饰符来显示该方法的调用者,即仅允许合约的拥有者 销毁合约。

2、工厂合约

工厂合约用于创建和部署子合约(资产),存储子合约地址以确保安全性和防止数据丢失。常用于销售资产并跟踪资产所有者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
contract CarShop {
   address[] carAssets;
   function createChildContract(string brand, string model) public payable {
      // insert check if the sent ether is enough to cover the car asset ...
      address newCarAsset = new CarAsset(brand, model, msg.sender);            
      carAssets.push(newCarAsset);   
   }
   function getDeployedChildContracts() public view returns (address[]) {
      return carAssets;
   }
}

contract CarAsset {
   string public brand;
   string public model;
   address public owner;
   function CarAsset(string _brand, string _model, address _owner) public {
      brand = _brand;
      model = _model;
      owner = _owner;
   }
}

代码address newCarAsset = new CarAsset(...)将触发一个交易来部署子合约并返回该合约的地址。 由于工厂合约和资产合约之间唯一的联系是变量address[] carAssets,所以一定要正确保存子合约的地址。

3、名称注册表

名称注册表模式通过合约名称到地址的映射表,简化了依赖多个合约的DApp的开发。通过固定一个合约地址,可以轻松查找合约地址,更新合约时不影响DApp的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
contract NameRegistry {
   struct ContractDetails {
      address owner;
      address contractAddress;
      uint16 version;
   }
   mapping(string => ContractDetails) registry;
   function registerName(string name, address addr, uint16 ver) returns (bool) {
      // versions should start from 1
      require(ver >= 1);
      
      ContractDetails memory info = registry[name];
      require(info.owner == msg.sender);
      // create info if it doesn't exist in the registry
       if (info.contractAddress == address(0)) {
          info = ContractDetails({
             owner: msg.sender,
             contractAddress: addr,
             version: ver
          });
       } else {
          info.version = ver;
          info.contractAddress = addr;
       }
       // update record in the registry
       registry[name] = info;
       return true;
   }
    function getContractDetails(string name) constant returns(address, uint16) {
      return (registry[name].contractAddress, registry[name].version);
   }
}

你的DApp将使用getContractDetails(name)来获取指定合约的地址和版本。

4、映射表迭代器

映射表迭代器模式解决了Solidity中映射表无法迭代的问题,通过将键值对存储在数组中实现迭代操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
contract MappingIterator {
   mapping(string => address) elements;
   string[] keys;
   function put(string key, address addr) returns (bool) {
      bool exists = elements[key] == address(0)
      if (!exists) {
         keys.push(key);
      }
      elements[key] = addr;
      return true;
    }
    function getKeyCount() constant returns (uint) {
       return keys.length;
    }
    function getElementAtIndex(uint index) returns (address) {
       return elements[keys[index]];
    }
    function getElement(string name) returns (address) {
       return elements[name];
    }
}

实现put()函数的一个常见错误,是通过遍历来检查指定的键是否存在。正确的做法是 elements[key] == address(0)。虽然遍历检查的做法不完全是一个错误,但它并不可取, 因为随着keys数组的增长,迭代成本越来越高,因此应该尽可能避免迭代。

5、提款模式

提款模式用于退款操作,避免在退款过程中出现异常导致整个交易被回滚。建议使用withdrawFunds()方法单独按需退款给调用者,而不是一次性退款给所有买家。

1
2
3
4
5
6
7
8
9
10
11
12
13
contract WithdrawalContract {
   mapping(address => uint) buyers;
   function buy() payable {
      require(msg.value > 0);
      buyers[msg.sender] = msg.value;
   }
   function withdraw() {
      uint amount = buyers[msg.sender];
      require(amount > 0);
      buyers[msg.sender] = 0;      
      require(msg.sender.send(amount));
   }
}

五种模式优劣性解析:  

  1. 自毁合约:自毁合约模式用于终止一个合约并从区块链中永久删除。这种模式常用于一次性合约或需要在特定条件下终止的合约。通过调用自毁函数(selfdestruct)并指定一个地址,合约的余额将被转移到该地址,并且合约的代码和存储将被删除。

  2. 工厂合约:工厂合约模式用于创建和部署子合约。工厂合约负责管理子合约的创建过程,并存储子合约的地址以确保安全性和方便访问。这种模式常用于创建多个相似的合约实例,例如创建代币合约或其他可复制的资产。

  3. 名称注册表:名称注册表模式通过将合约名称映射到地址的表来简化依赖多个合约的去中心化应用(DApp)的开发。通过使用注册表合约,可以通过固定的合约地址轻松查找和更新合约,而不需要在DApp的代码中硬编码合约地址,从而提高了灵活性和可维护性。

  4. 映射表迭代器:Solidity中的映射表无法直接迭代,但通过映射表迭代器模式可以解决这个问题。该模式通过将键值对存储在数组中,以特定的顺序记录映射表中的键,并提供函数来遍历数组并返回键值对的详细信息,从而实现对映射表的迭代操作。

  5. 提款模式:提款模式用于在合约中进行退款操作,以防止在退款过程中出现异常导致整个交易被回滚。通常建议使用提款模式时,将退款金额存储在合约中,然后通过调用合约的withdrawFunds()方法,单独按需退款给调用者,而不是一次性退款给所有的买家。这样可以确保退款操作的可靠性,并避免因异常而导致整个退款过程失败。文章来源地址https://www.toymoban.com/news/detail-848839.html

到了这里,关于设计模式:智能合约的经典设计模式及解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 经典的设计模式16——观察者模式

    定义: 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使得他们能够自动更新自己。 目标和观察者:一对多 单向依赖。通知的顺序绝不依赖于通知的顺序,多个观察者之间的功能是平行的

    2024年02月09日
    浏览(35)
  • 设计模式系列:经典的单例模式

    单例模式,是设计模式当中非常重要的一种,在面试中也常常被考察到。 正文如下: 一、什么时候使用单例模式? 单例模式可谓是23种设计模式中最简单、最常见的设计模式了,它可以保证一个类只有一个实例。我们平时网购时用的购物车,就是单例模式的一个例子。想一

    2024年02月15日
    浏览(43)
  • 设计模式——经典单例

    // 构造、析构函数私有化(一个进程只允许一个对象存在) // 对象私有化、静态化(因为接口静态函数) // 对象调用接口静态化(因为静态函数脱离了类对象,可以直接调用) 唯一的对象在使用时才进行初始化。存在多线程问题。 唯一的对象在定义时就完成初始化。

    2024年02月12日
    浏览(34)
  • <JavaEE> 经典设计模式之 -- 线程池

    目录 一、线程池的概念 二、Java 标准库中的线程池类 2.1 ThreadPoolExecutor 类 2.1.1 corePoolSize 和 maximumPoolSize 2.1.2 keepAliveTime 和 unit 2.1.3 workQueue 2.1.4 threadFactory 2.1.5 handler 2.1.6 创建一个参数自定义的线程池 2.2 Executors 类 2.3 实现自己的线程池 1)什么是线程池? 准备预期需要使

    2024年02月05日
    浏览(29)
  • 《C++新经典设计模式》之第15章 适配器模式

    适配器模式.cpp

    2024年02月03日
    浏览(46)
  • 8. Fabric2.2 区块链农产品溯源系统 - 智能合约设计

    根据上小节的需求分析与方案设计来进行智能合约的设计。 智能合约设计最核心的是存储字段的设计、也就是索引设计,Fabric 常见的时间状态存储引擎是LevelDB 或 CouchDB,这两个数据库是KV存储,KV存储不像SQL类型存储,一张表创建多个字段,多个字段索引可以进行各种复查询

    2023年04月08日
    浏览(40)
  • 【设计模式】代理模式例子解析

    代理模式,顾名思义,就是我们在需要访问一个类时,并不直接调用这个类,而是通过一个\\\"代理\\\"来间接地实现这个过程。 这个“代理”就像是真实对象的一个接口,所有的对于真实对象的操作都需要通过这个“代理”来实现。“郑重其事的代理”,这或许是代理模式的最好

    2024年01月25日
    浏览(36)
  • 区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第一套智能合约安全漏洞测试(0基础版)

    第一套题的智能合约安全漏洞测试题目 漏洞合约代码 总结: EtherStore合约 是一个简单的储蓄合约,用户可以存入和提取以太币。 Attack合约 是针对 EtherStore 合约设计的,它包含了一个构造函数来引用目标 EtherStore 合约 ,并提供了一个 attack 函数 ,试图通过先存入再立即提取

    2024年04月11日
    浏览(51)
  • 区块链的设计模式 blockchain SMR BCML DML

    2.4.1 Blockchain 区块链模式 公有链(以太坊等) Blockchain is as we have described it, and includes many of so-called public chains or public ledgers, which are permissionless to join. 2.4.2 State Machine Replication (SMR) 复制状态机 联盟链(Hyperledger Fabric) SMR includes many of so-called private chains, consortium chains or private

    2024年02月13日
    浏览(34)
  • 万字解析设计模式之原型模式与建造者模式

    原型模式是一种创建型设计模式,其目的是使用已有对象作为原型来创建新的对象。 原型模式的核心是克隆 ,即通过复制已有对象来创建新对象,而不是通过创建新对象的过程中独立地分配和初始化所有需要的资源。这种方式可以节省创建对象的时间和资源,特别是在创建

    2024年02月06日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包