智能合约的现状

以太坊在区块链上实现了智能合约的概念,用于:同质化通证发行(ERC-20)、众筹、投票、存证取证等等,共同点是:合约逻辑简单,只是业务流程中的关键节点,而非整个业务流程。而智能合约想解决的信任传递,是环环相扣的,如果在传统系统环节被恶意侵入和篡改数据,那么传入智能合约的数据就是不受到信任的。因此,整体业务流程上链是智能合约发展的趋势。

  

智能合约的局限

智能合约在早期被设计的时候,并不打算支撑复杂的业务体系,这和它设计的初衷相违背:漏洞往往出现在程序员编写的代码和他想实现的逻辑之间存在着差距,越是简单的代码越是安全。简单和受限访问成了智能合约安全可靠的保障。

因此,智能合约引入了隔离网络和文件系统的沙箱环境、基于栈的编译器(有限高度的栈深以及仅可访问栈顶16个元素的限制)、静态语言、gasLimit(限定了合约的大小,每个合约能处理的逻辑有限;限定每个函数逻辑的复杂度,每一步操作都会消耗gas,以至于连使用循环都成了奢侈)、严格的内存访问限制(每个合约仅可以访问自己的存储单元),这就导致了智能合约不同于传统编程语言,自身就带着诸多限制。

目前,智能合约仍然处于发展的早期阶段,配套的工具、成熟的框架、第三方包寥寥可数。因此编写复杂业务场景的智能合约,只能从底层的逻辑开始编写:编写数据库模型CURD、跨合约数据交互、增强基本数据类型功能(string类型的slice、array的delete),导致开发合约速度的缓慢。

另外,由于区块链的另外一个特性:防篡改。这导致了智能合约部署上链后,任何人包括合约所有者都不能再进行修改。意味着智能合约无法像传统应用那样实现敏捷开发,合约的每一个方法都需要进过大量测试,保证整个合约的正确性严谨性。即使保证合约不出问题,但业务的需求并非一成不变,业务变动,智能合约无可避免的跟着变动,那么意味着合约的重新部署,但是旧合约的数据是无法转移到新合约上的;已部署好的合约如果存在漏洞被恶意攻击,需要有方法能够尽快停止合约运行,保证用户数据不被篡改,留出时间让智能合约的编写者快速修复漏洞。因此,合约的升级和管理需要设计。

智能合约目前的发展方向

编写智能合约的程序员目前分为两派,一派主张合约尽可能的精简,只有简单才不容易出现错误,只有关键部分上链部分;另一派主张信任传递的闭环,也就是说整个业务逻辑尽可能多的上链,例如Polymath,ConsenSys,它们将完整的业务流程利用智能合约的方式实现。

轻量级的智能合约并没有太多的技术难点可讲,真正需要发展的是智能合约设计模式。

目前,已有的官方推荐的工具集, Zeppelin,它提供了:

  • 数学计算
  • 合约所有权
  • 编码解码
  • 加密解密

方便合约编写者调用,但这些只能是以工具、参考的形式存在,并不能算作真正意义上的设计模式。目前Zeppelin社区也在积极探索智能合约设计模式的实现方式。

Zeppelin社区目前构思了智能合约与逻辑分离的设计模式,用于解决智能合约升级的问题。

  原文地址: https://blog.openzeppelin.com/proxy-libraries-in-solidity-79fbe4b970fd/

如何利用智能合约实现复杂的业务场景

  目前受限于智能合约的限制,只能实现业务场景中的关键步骤,如果将整个业务放到链上执行,传统智能合约的编写方式将不再适用,例如无法解决合约文件大小的瓶颈、参数过多导致栈深错误、合约之间互相访问存储数据的问题等等,这些都会影响智能合约的编写。目前如何编写能够承载负责业务场景的智能合约,已经成为行业共同面临的挑战之一。

  在这里,我参照传统MVC设计模式、基于关系型数据库存储,结合智能合约自身特性,Zeppelin社区提供的合约分离理念,初步实现复杂业务场景的智能合约设计模式。

  一、针对业务功能处理

  每个业务场景包括多个角色,角色既有单独操作,也有与其他角色共同配合的操作。

  针对角色,将其合约拆分成为:入口合约、存储合约、逻辑合约。

  1) 设计存储合约,用于存储角色模型的数据,并提供对外访问的CURD方法,实现效果等同于MVC中的Model层。

  2) 设计逻辑实现合约,利用存储合约提供的CURD,实现业务逻辑。类比于MVC中的Controller层。

  3) 设计入口合约,用于提供对外访问的地址,将用户的请求转发至逻辑合约进行处理,执行的结果存入存储合约中。

  二、针对业务变动及风险处理

  考虑到业务会发生变动。将传统智能合约拆分成:入口合约、存储合约、逻辑合约,三个合约各司其职,共同实现业务,当业务发生变动需要修改,修改并重新部署逻辑合约,并将新版本的逻辑合约注册到入口合约,即可以解决

  1、 合约可实现性:突破合约大小限制、函数复杂度限制

  2、 合约可升级性:地址不变,只对合约功能进行升级

  3、 合约可维护性:发现bug时,及时对合约进行修复

  另外,智能合约继承自功能开关合约,可以实现当智能合约发现漏洞时,紧急关闭某些功能(例如转账),减少损失。

  三、针对业务角色之间的交互处理

  智能合约中,数据的记录都是Key-Value形式,类似于Redis这样的数据库,数据之间的关联较弱。通过设置各个合约都可以访问的全局存储合约,记录各个入口合约的地址、合约数据之间的关联关系,使各个合约之间可以数据互通。

  四、针对业务场景中的执行权限处理

  智能合约继承自所有权合约,可以限制合约中某些关键方法的操作者,这些操作者可以是个人账户、也可以是合约账户,使合约受控于系统管理员。另外,也提供了权限转移功能,可以方便的将权限转移给其他管理员。

智能合约设计模式的技术点

  l  委托调用

以上智能合约的拆分,就是依赖智能合约中委托调用的特性。

委托调用,会保留调用者的账户与信息,例如User调用合约A中funcA,funcA委托调用合约B中的funcB,那么funcB的调用者就是User,而不是合约A。委托调用的优势就是可以保留调用合约的上下文,只是利用合约B的代码实现想要的功能。这样可以:

  • 减少合约A中的代码量。
  • 合约B中的逻辑可以随时更新。

  l  Fallback机制

  当调用智能合约中未定义的方法时,智能合约会将调用者及参数都传给一个错误处理函数,类似访问了网站中不存在的页面,会跳转到404页面一样。正是利用了这个特性,合约A(上文例子)将在这个fallback函数中统一处理这个未定义方法。

  l  内联汇编

  智能合约中的委托调用,只会返回调用结果是True和False,但我们要达成智能合约的拆分,就要让委托调用返回调用后的结果,这就需要修改委托调用的指令集,将结果返回。通过内联汇编,修改智能合约中委托调用的实现。

  l  全局存储合约

  全局存储合约是模拟传统key-value数据库,通过智能合约的方式实现数据库的CURD,将系统的配置(比如管理员的地址、Token与稳定货币的兑换比例等)、各个模块入口合约的地址、合约之间的关联关系存储起来,打通各个合约之间的数据。

  l  合约的合理拆分

  目前将合约拆分为入口合约、存储合约、逻辑合约。

  入口合约:所有与合约的交互都是通过入口合约。入口合约记录了存储合约地址:通过委托调用转发给逻辑合约处理,修改存储合约数据。记录了逻辑合约的地址和版本:知道该转发给哪个版本的逻辑合约处理。

  存储合约:负责存储数据,合约的存储结构不能变,这是底线。类比数据库中的表,一旦设定就不能轻易修改;访问及修改数据的接口,其他合约不能直接访问当前合约的数据,需要通过外部函数来访问和修改,例如java model中的setter和getter 方法,实现存储合约的的CURD。

  逻辑合约:负责处理合约逻辑,通过组合存储合约的CURD,实现复杂的逻辑。

智能合约框架

  l  模块框架

  1、 用户调用入口合约函数。

  2、 入口合约委托给逻辑合约处理。

  3、 逻辑合约进入到入口合约上下文,获取到存储合约地址,修改/查询存储合约数据。

  4、 逻辑合约返回数据给入口合约。

  5、 入口合约返回数据给用户。

  l  整体框架

  

智能合约设计模式的优缺点

优点:

  a) 拆分智能合约,可以绕过合约大小的限制,实现复杂的功能。

  b) 可以通过升级逻辑合约来更新智能合约。

  c) 可控的智能合约,当出现问题时,管理员账户可以关闭关键性操作。

  d) 将功能性合约封装成通用合约,减少重复部署合约消耗的gas。

  e) 通用全局存储,可以满足任意格式数据的存储与读取。

  f) 合约注册表,可以方便合约之间的互相调用。

缺点:

  a) 拆分智能合约,合约总体代码量增加,增加了部署时gas的消耗。

  b) 合约的可读性大幅下降,用户无法简单的读取合约的逻辑。

  c) 键值对的存储合约操作复杂。【智能合约】编写复杂业务场景下的智能合约——可升级的智能合约设计模式

Demo地址:https://github.com/NoharaHiroshi/upgradability-solidity-demo

【智能合约】编写复杂业务场景下的智能合约——可升级的智能合约设计模式(附Demo)的更多相关文章

  1. 高CPU业务场景下的任务分发方案Gearman搭建一览

      Gearman是当年LiveJournal用来做图片resize的,大家也明白图片resize是一个高CPU的操作,如果让web网站去做这个高CPU的功能,有可能会拖垮你的 web应用,那本篇我们 ...

  2. MvcPager.js在特定业务场景下的问题解决

    用到了MvcPager.js,在一个常见的场景中出现了不能POST表单数据的问题,场景描述如下: 日期:2012-12-12 编号:*****                             ...

  3. 各业务场景下的技术推荐 【.net】

    后端: 1.webapi的token加密:  1)JWT验证算法,不推荐:2)RSA 2.集合的扩展:C5.dll 3.对象映射工具:AutoMapper .TinyMapper 4.任务调度框架:Q ...

  4. 拨乱反正:DDD 回归具体的业务场景,Domain Model 再再重新设计

    首先,把最真挚的情感送与梅西,加油! 写在前面 阅读目录: 重申业务场景 Domain Model 设计 后记 上一篇<设计窘境:来自 Repository 的一丝线索,Domain Model ...

  5. DDD 回归具体的业务场景,Domain Model 再再重新设计

    DDD 回归具体的业务场景,Domain Model 再再重新设计 首先,把最真挚的情感送与梅西,加油! 写在前面 阅读目录: 重申业务场景 Domain Model 设计 后记 上一篇<设计窘 ...

  6. Vue ElementUI Tree组件 回显问题(设置选择父级时会全选所有的子级,有此业务场景是不适合的)

    业务场景下有这样的问题 业务需求需要保存前端 半选节点 解决方案 let checked = this.$refs.menuTree.getCheckedKeys(); //此方法获取半选节点 let ...

  7. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...

  8. EOS 智能合约编写(一)

    本文编写了一个简单的EOS智能合约,实现用户管理和资产管理,包括存钱,取钱,转帐的功能,旨在学习如何编写自己的EOS合约功能. 系统:Ubuntu      EOS版本:v1.1.1 一.智能合约代码 ...

  9. 数栈运维实例:Oracle数据库运维场景下,智能运维如何落地生根?

    从马车到汽车是为了提升运输效率,而随着时代的发展,如今我们又希望用自动驾驶把驾驶员从开车这项体力劳动中解放出来,增加运行效率,同时也可减少交通事故发生率,这也是企业对于智能运维的诉求. 从人工运维到自 ...

随机推荐

  1. PhpStorm terminal无法输入命令的解决方法

    下面小编就为大家带来一篇PhpStorm terminal无法输入命令的解决方法.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧   在使用PhpStorm时,点击下面的 ...

  2. P1029 栈的基础操作

    题目描述 现在给你一个栈,它一开始是空的,你需要模拟栈的操作.栈的操作包括如下: "push x":将元素 x 放入栈中,其中x是一个int范围内的整数: "pop&qu ...

  3. 使用Python内置的smtplib包和email包来实现邮件的构造和发送。

    此文章github地址:https://github.com/GhostCNZ/Python_sendEmail Python_sendEmail 使用Python内置的smtplib包和email包 ...

  4. win10 uwp 好看的时间选择控件

    本文告诉大家我找到的好看的时间选择控件 先给大家看一下图,然后就知道我说的是什么 首先需要安装 Nuget ,搜索 DeanChalk.UWP.TimePicker 或输入Install-Packag ...

  5. C# 如何写 DEBUG 输出

    本文来告诉大家一个规范,如何去写 DEBUG 的输出. 经常在代码中,需要使用 DEBUG 来输出一些奇怪的东西来进行测试.但是输出的窗口只有一个,如果有一个逗比在不停输出,那么就会让输出窗口看不到自 ...

  6. 【16.50%】【CF 44G】Shooting Gallery

    time limit per test 5 seconds memory limit per test 256 megabytes input standard input output standa ...

  7. 布尔&list与条件循环语句与trutle

    布尔值与空值 布尔值: 一个布尔值只有True.False两种值 空值: 是python里一个特殊的值,用None表示.None不能理解为0.因为0是有意义的,而None是一个特殊值. list(列表 ...

  8. 编写jQuery插件的方法和注意点

    编写jQuery插件的方法和注意点 插件的种类 jQuery的插件主要分为3种类型. 1. 封装对象方法的插件 这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是最常见的 ...

  9. IPv4数据报格式及其语义

    一.IP数据报的格式如下图所示 版本 首部长度 服务类型 数据报长度 16比特标识 标志 13比特片偏移 寿命 上层协议 首部检验和 32比特源IP地址 32比特目的IP地址 选项(如果有的话) 数据 ...

  10. Excel快速填充

    利用单元格右下角填充句柄进行填充 然后选择快速填充 利用数据面板的快速填充功能(ctrl+e) 年月日三列不能同时填充 只能够一列一列的填充 类别取第一列 级别取第二列 但是由于第一个的编号有两个“1 ...