智能合约设计模式

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

设计模式是许多开发场景中的首选解决方案,本文将介绍五种经典的智能合约设计模式并给出以太坊solidity实现代码:自毁合约、工厂合约、名称注册表、映射表迭代器和提款模式。

1、自毁合约

合约自毁模式用于终止一个合约,这意味着将从区块链上永久删除这个合约。 一旦被销毁,就不可能调用合约的功能,也不会在账本中记录交易。

现在的问题是:“为什么我要销毁合约?”。

有很多原因,比如某些定时合约,或者那些一旦达到里程碑就必须终止的合约。 一个典型的案例是贷款合约,它应当在贷款还清后自动销毁;另一个案例是基于时间的拍卖合约,它应当在拍卖结束后终止 —— 假设我们不需要在链上保存拍卖的历史记录。

在处理一个被销毁的合约时,有一些需要注意的问题:

  • 合约销毁后,发送给该合约的交易将失败
  • 任何发送给被销毁合约的资金,都将永远丢失

为避免资金损失,应当在发送资金前确保目标合约仍然存在,移除所有对已销毁合约的引用。 现在我们来看看代码:

contract SelfDesctructionContract {public address owner;public string someValue;modifier ownerRestricted {require(owner == msg.sender);_;} // constructorfunction SelfDesctructionContract() {owner = msg.sender;}// a simple setter functionfunction setSomeValue(string value){someValue = value;} // you can call it anything you wantfunction destroyContract() ownerRestricted {suicide(owner);}
}

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

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

2、工厂合约

工厂合约用于创建和部署“子”合约。 这些子合约可以被称为“资产”,可以表示现实生活中的房子或汽车。

工厂用于存储子合约的地址,以便在必要时提取使用。 你可能会问,为什么不把它们存在Web应用数据库? 这是因为将这些地址数据存在工厂合约里,就意味着是存在区块链上,因此更加安全,而数据库的损坏可能会造成资产地址的丢失,从而导致丢失对这些资产合约的引用。 除此之外,你还需要跟踪所有新创建的子合约以便同步更新数据库。

工厂合约的一个常见用例是销售资产并跟踪这些资产(例如,谁是资产的所有者)。 需要向负责部署资产的 函数添加payable修饰符以便销售资产。 代码如下:

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使用了ClothesFactoryContract、GamesFactoryContract、BooksFactoryContract等多个合约。

现在想象一下,将所有这些合约的地址写在你的应用代码中。 如果这些合约的地址随着时间的推移而变化,那该怎么办?

这就是名称注册表的作用,这个模式允许你只在代码中固定一个合约的地址,而不是数十、数百甚至数千个 地址。它的原理是使用一个合约名称 => 合约地址的映射表,因此可以通过调用getAddress("ClothesFactory") 从DApp内查找每个合约的地址。 使用名称注册表的好处是,即使更新那些合约,DApp也不会受到任何影响,因为我们只需要修改映射表中合约的地址。

代码如下:

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 1require(ver >= 1);ContractDetails memory info = registry[name];require(info.owner == msg.sender);// create info if it doesn't exist in the registryif (info.contractAddress == address(0)) {info = ContractDetails({owner: msg.sender,contractAddress: addr,version: ver});} else {info.version = ver;info.contractAddress = addr;}// update record in the registryregistry[name] = info;return true;}function getContractDetails(string name) constant returns(address, uint16) {return (registry[name].contractAddress, registry[name].version);}
}

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

4、映射表迭代器

很多时候我们需要对一个映射表进行迭代操作 ,但由于Solidity中的映射表只能存储值,并不支持迭代,因此映射表迭代器模式非常有用。 需要指出的是,随着成员数量的增加,迭代操作的复杂性会增加,存储成本也会增加,因此请尽可能地避免迭代。

实现代码如下:

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、提款模式

假设你销售汽车轮胎,不幸的是卖出的所有轮胎出问题了,于是你决定向所有的买家退款。

假设你跟踪记录了合约中的所有买家,并且合约有一个refund()函数,该函数会遍历所有买家并将钱一一返还。

你可以选择 - 使用buyerAddress.transfer()或buyerAddress.send() 。 这两个函数的区别在于,在交易异常时,send()不会抛出异常,而只是返回布尔值false ,而transfer()则会抛出异常。

为什么这一点很重要?

假设大多数买家是外部账户(即个人),但一些买家是其他合约(也许是商业)。 假设在这些买方合约中,有一个合约,其开发者在其fallback函数中犯了一个错误,并且在被调用时抛出一个异常,fallback()函数是合约中的默认函数,如果将交易发送到合同但没有指定任何方法,将调用合约的fallback()函数。 现在,只要我们在refund函数中调用contractWithError.transfer() ,就会抛出异常并停止迭代遍历。 因此,任何一个买家合约的fallback()异常都将导致整个退款交易被回滚,导致没有一个买家可以得到退款。

虽然在一次调用中退款所有买家可以使用send()来实现,但是更好的方式是提供withdrawFunds()方法,它 将单独按需要退款给调用者。 因此,错误的合约不会应用其他买家拿到退款。

实现代码如下:

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));}
}

转载于:https://my.oschina.net/u/3837977/blog/1808827

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用1Password,Authy和Privacy.com外包您的在线安全性

Take some work off your plate while beefing up security with three changes you can make today.通过今天可以进行的三项更改来增强安全性,同时省下一些工作。 Unstable times are insecure times, and we’ve already got enough going on to deal with. When…

「CodePlus 2017 12 月赛」火锅盛宴

n<100000种食物&#xff0c;给每个食物煮熟时间&#xff0c;有q<500000个操作&#xff1a;在某时刻插入某个食物&#xff1b;查询熟食中编号最小的并删除之&#xff1b;查询是否有编号为id的食物&#xff0c;如果有查询是否有编号为id的熟食&#xff0c;如果有熟食删除之…

5815. 扣分后的最大得分

给你一个 m x n 的整数矩阵 points &#xff08;下标从 0 开始&#xff09;。一开始你的得分为 0 &#xff0c;你想最大化从矩阵中得到的分数。 你的得分方式为&#xff1a;每一行 中选取一个格子&#xff0c;选中坐标为 (r, c) 的格子会给你的总得分 增加 points[r][c] 。 然…

您有一个上云锦囊尚未领取!

前期&#xff0c;我们通过文章《确认过眼神&#xff1f;上云之路需要遇上对的人&#xff01;》向大家详细介绍了阿里云咨询与设计场景下的五款专家服务产品&#xff0c;企业可以通过这些专家服务产品解决了上云前的痛点。那么&#xff0c;当完成上云前的可行性评估与方案设计后…

怎么从运营转到前端开发_我如何在16个月内从销售人员转到前端开发人员

怎么从运营转到前端开发On August 18, 2015, I was on a one-way flight headed to Copenhagen from Toronto Pearson Airport. I was starting my two semester exchange at the Copenhagen Business school. 2015年8月18日&#xff0c;我乘坐单程飞机从多伦多皮尔逊机场前往哥…

Python os.chdir() 方法

概述 os.chdir() 方法用于改变当前工作目录到指定的路径。 语法 chdir()方法语法格式如下&#xff1a; os.chdir(path) 参数 path -- 要切换到的新路径。 返回值 如果允许访问返回 True , 否则返回False。 实例 以下实例演示了 chdir() 方法的使用&#xff1a; #!/usr/bin/pyth…

oracle认证考试_Oracle云认证–通过此3小时免费课程通过考试

oracle认证考试This Oracle Cloud Certification exam will take – on average – about one week of study to prepare for. Most people who seriously commit to their studies are ready to pass the exam within about four days.这项Oracle Cloud认证考试平均需要大约一…

git 修改远程仓库源

自己已经写好了一个项目&#xff0c;想上传到 github github 创建新项目 新建 README.md &#xff0c; LICENSE 本地项目添加 github 远程仓库源 不是git项目git remote add origin https://USERNAME:PASSWORDgithub.com/USERNAME/pro.git已是git项目&#xff0c;先删除再添加 …

Docker 常用命令备忘录

build镜像docker build -t"name" . 复制代码后台运行docker run -d -i -t 14a21c118315 /bin/bash 复制代码删除镜像docker image rmi -f 300de37c15f9 复制代码停止运行的镜像docker ps docker kill (id) 复制代码进入镜像docker attach 29f2ab8e517c(ps id) 复制…

mvp最小可行产品_最低可行产品–如何为您的项目建立MVP以及为什么要这样做

mvp最小可行产品具有足够功能的产品可以收集全面的定性反馈 (A product with just enough features to gather comprehensive qualitative feedback) Proof of concept, prototypes, wireframes, mockups… what actually constitutes a Minimum Viable Product (MVP)?概念验证…

composer 更改为中国镜像

composer 更改为中国镜像 $ composer config -g repo.packagist composer https://packagist.phpcomposer.com 转载于:https://www.cnblogs.com/love-snow/articles/8111410.html

人人都能学会的python编程教程(基础篇)完整版

人人都能学会的python编程教程1&#xff1a;第一行代码 人人都能学会的python编程教程2&#xff1a;数据类型和变量 人人都能学会的python编程教程3&#xff1a;字符串和编码 人人都能学会的python编程教程4&#xff1a;关系运算符与循环 人人都能学会的python编程教程5&#x…

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外&#xff0c;其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n)&#xff0c;空间复杂度是O(1)。 示例 1&#xff1a; 输入&#xff1a;nums [4,1,4,6] 输出&#xff1a;[1,6] 或 [6,1] 示例 2&#xff1a…

表达爱意的程序_如何像程序员一样表达爱意❤️

表达爱意的程序Today is Valentines Day! &#x1f60d; 今天是情人节&#xff01; &#x1f60d; How nice would it be if you sent a Romantic Message every hour to your loved one? But even better... 如果您每小时向您所爱的人发送一封浪漫的短信&#xff0c;那将有多…

工作中的小问题

1、a标签的选择问题 需要修改带class的a标签的hover的文字颜色&#xff0c;方式如下 <style>a.egHyperlink:hover{color:red;} </style> <a href"#" class"egHyperlink">smile</a> 复制代码2、hr分割线 需要一条粉红色的分割线&am…

More DETAILS! PBR的下一个发展在哪里?

最近几年图形学社区对PBR的关注非常高&#xff0c;也许是由于Disney以及一些游戏引擎大厂的助推&#xff0c;也许是因为它可以被轻松集成进实时渲染的游戏引擎当中&#xff0c;也许是因为许多人发现现在只需要调几个参数就能实现具有非常精细细节的表面着色了。反正现在网络上随…

sql server 2008 身份验证失败 18456

双击打开后加上 ;-m 然后以管理员方式 打开 SQLSERVER 2008 就可以已window身份登录 不过还没有完 右键 属性 》安全性 更改为 sql server 和 window身份验证模式 没有sql server登陆账号的话创建一个 然后把-m去掉就可以用帐号登录了 转载于:https://www.cnblogs.com/R…

js 两个方法

//js in_array方法function in_array(all,one) { for(i0;i<all.length;i) { if(all[i] one) return true; } return false; } //js in_array方法/*** 一维数组去重方法** param arr 需要去重数组* returns {Array} 返回已经去重数组*/function unique(arr) {var ret [];va…

敏捷数据科学pdf_如何将敏捷框架应用于数据科学项目

敏捷数据科学pdfIn this article, well discuss how agile principles and values can be applied to the way you approach data science projects.在本文中&#xff0c;我们将讨论如何将敏捷性原则和价值观应用于您处理数据科学项目的方式。 Project management methodologi…

剑指 Offer 56 - II. 数组中数字出现的次数 II

在一个数组 nums 中除一个数字只出现一次之外&#xff0c;其他数字都出现了三次。请找出那个只出现一次的数字。 示例 1&#xff1a; 输入&#xff1a;nums [3,4,3,3] 输出&#xff1a;4 示例 2&#xff1a; 输入&#xff1a;nums [9,1,7,9,7,9,7] 输出&#xff1a;1 限制…